Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Lock bugfixes - missing lock deinits This also adds deinit calls in the linux_module...
[palacios.git] / linux_module / iface-host-dev.c
1 /* 
2  * Host device interface + user-space device interface
3  * (c) 2011 Peter Dinda
4  */
5
6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.h>
9 #include <linux/fs.h>
10 #include <linux/uaccess.h>
11 #include <linux/poll.h>
12 #include <linux/anon_inodes.h>
13 #include <linux/file.h>
14 #include <linux/sched.h>
15 #include <linux/delay.h>
16
17 #include <interfaces/vmm_host_dev.h>
18
19 #include "palacios.h"
20 #include "iface-host-dev.h"
21 #include "linux-exts.h"
22 #include "vm.h"
23
24 /*
25   There are two things in this file:
26
27
28   1. An implementation of the Palacios host device interface that will
29      accept any URL from Palacios.  Currently, the only URL type it will
30      handle is user:<name>, but it should be clear how to extend with
31      other types.
32
33      Palacios opens a host device by issuing something like this:
34
35          palacios_host_dev_open( impl="user:foo" busclass=pci, opaque )
36
37      This will attempt to rendezvous with the user space device The
38      rendevzous retry and timeout periods can be set below.
39
40   2. An implementation of user: urls - the host interface is mapped
41      into an RPC-like interface to/from user space via a file
42      interface.   
43
44      The user space gets a file descriptor like this:
45
46      int vmfd = open("/dev/v3-vmX",...);
47
48      int devfd = ioctl(vmfd,V3_HOST_DEV_CONNECT,"user:foo"); 
49
50      This will attempt to rendezvous with the host side.
51
52      If it returns successfully, you can now issue synchronous,
53      blocking RPCs to the guest to read/write its memory and inject
54      irqs.  This means that a user->host request is handled
55      immediately, and independently of any host->user request. 
56
57      struct palacios_host_dev_user_op op;
58
59      // fill out op
60      op.type = PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST; 
61      ...
62
63      ioctl(devfd, V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL, &op);
64
65      // return value is # bytes read or written; or 0 if irq injected
66      // negative value is error
67
68      The interface from the host to the user side is asynchronous
69      blocking RPC.  Any host device will have at most one outstanding
70      request from palacios.  The implementation here stores the
71      request until the user side is ready to accept it.  The user side
72      can check if there is a request via a poll/select or an ioctl.
73      The ioctl also returns the needed size for the request structure.
74      After the user side has a request, it is expected to process it,
75      perhaps making user->host requests as described above, and then
76      return a response.  Only one host->user request should be in
77      progress at any time in the user space.
78
79      What this looks like is:
80      
81      poll(...devfd for read...) or select(...devfd for read...)
82
83      if (devfd is marked readable) { 
84          uint64_t size;
85
86          ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&size);
87          // returns 1 if there is a request, 0 if not, negative on err
88
89          struct palacios_host_dev_host_request_response *req;
90
91          req = allocate req to be at least size bytes long
92
93          ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL,req)
94          // returns 1 if there is a request, 0 if not, negative on err
95          
96          // process request, perhaps using above user->host request
97          // build response structure
98          // resp.data_len == size of structure including relevant data at end
99
100          ioctl(devfd,V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL,resp);
101          // returns 0 if there is no outstanding request (user error)
102          // 1 on success, negative on error
103      }
104     
105      Note that the current model has deferred rendezvous and allows
106      for user-side device disconnection and reconnection.  It is important
107      to note that this implementation does NOT deal with state discrepency
108      between the palacios-side and the user-side.   For example, a user-side
109      device can disconnect, a palacios-side request can then fail, and 
110      when the user-side device reconnects, it is unaware of this failure.  
111
112 */
113
114
115 struct palacios_host_dev {
116     spinlock_t      lock;
117     struct list_head devs;
118 };
119
120
121 #define MAX_URL 256
122
123 #define RENDEZVOUS_WAIT_SECS  60
124 #define RENDEZVOUS_RETRY_SECS 1
125
126 #define DEEP_DEBUG    0
127 #define SHALLOW_DEBUG 0
128
129 #if DEEP_DEBUG
130 #define DEEP_DEBUG_PRINT(fmt, args...) DEBUG((fmt), ##args)
131 #else
132 #define DEEP_DEBUG_PRINT(fmt, args...) 
133 #endif
134
135 #if SHALLOW_DEBUG
136 #define SHALLOW_DEBUG_PRINT(fmt, args...) INFO((fmt), ##args)
137 #else
138 #define SHALLOW_DEBUG_PRINT(fmt, args...) 
139 #endif
140
141
142 struct palacios_host_device_user {
143     spinlock_t lock;
144     int      connected;    // is the user space connected to this?
145     int      waiting;      // am I waiting for a user-space response?
146
147     int      fd;           // what is the user space fd?
148
149     char     url[MAX_URL]; // what is the url describing the device
150
151     v3_guest_dev_t guestdev; // what is the palacios-side device
152
153     wait_queue_head_t  user_wait_queue; // user space processes waiting on us (should be only one)
154     wait_queue_head_t  host_wait_queue; // host threads (should only be one) waiting on user space
155
156     struct v3_guest                                *guest; // my guest
157     struct palacios_host_dev_host_request_response *req;   // curent request
158     struct palacios_host_dev_host_request_response *resp;  // curent response
159
160     struct list_head  node;   // for adding me to the list of hostdevs this VM has
161 };
162
163
164 /**************************************************************************************
165   Utility functions
166 *************************************************************************************/
167
168 static void palacios_host_dev_user_free(struct palacios_host_device_user *dev)
169 {
170     if (dev->req) {
171         palacios_free(dev->req);
172         dev->req=0;
173     } 
174     if (dev->resp) { 
175         palacios_free(dev->resp);
176         dev->resp=0;
177     }
178     palacios_free(dev);
179 }
180
181
182 //
183 // Is this structure big enough for the data_size we will use?
184 //
185 // THIS FUNCTION CAN BE CALLED WHILE INTERRUPTS ARE OFF
186 //
187 static int palacios_bigenough_reqresp(struct palacios_host_dev_host_request_response *r, uint64_t data_size)
188 {
189     if (!r) { 
190         return 0;
191     } else {
192         if (((r->len)-sizeof(struct palacios_host_dev_host_request_response)) < data_size) {
193             return 0;
194         } else {
195             return 1;
196         }
197     }
198 }
199
200 //
201 // Resize a request/response structure so that it will fit data_size bytes
202 //
203 // At the end of this, *r->len >= sizeof(struct)+data_size
204 //
205 // THIS FUNCTION MAY SLEEP AS IT CALLS KMALLOC 
206 // DO NOT CALL IT WHILE HOLDING A SPIN LOCK WITH INTERRUPTS OFF
207 //
208 static int palacios_resize_reqresp(struct palacios_host_dev_host_request_response **r, uint64_t data_size, int copy)
209 {
210     
211     DEEP_DEBUG_PRINT("palacios: hostdev: resize 0x%p to %llu\n",*r,data_size);
212
213     if ((*r)==0) { 
214         // allocate it
215         DEEP_DEBUG_PRINT("palacios: hostdev: attempt alloc\n");
216         *r = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
217         DEEP_DEBUG_PRINT("palacios: hostdev: palacios_alloc done\n");
218         if ((*r)==0) { 
219             ERROR("palacios: hostdev: failed to allocate\n");
220             return -1;
221         } else {
222             (*r)->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
223             DEEP_DEBUG_PRINT("palacios: hostdev: allocated\n");
224             return 0;
225         }
226     } else {
227         //let it go if it's big enough
228         uint64_t cur_len = (*r)->len-sizeof(struct palacios_host_dev_host_request_response);
229
230         if (data_size<=cur_len) { 
231             // do nothing
232             DEEP_DEBUG_PRINT("palacios: hostdev: size ok\n");
233             return 0;
234         } else {
235             struct palacios_host_dev_host_request_response *new;
236
237             if (!copy) { 
238                 palacios_free(*r);
239                 *r=0;
240             }
241             new = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
242             if (!new) { 
243                 ERROR("palacios: hostdev: failed to reallocate\n");
244                 return -1;
245             } else {
246                 new->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
247                 if (copy) { 
248                     memcpy(new->data,(*r)->data,(*r)->data_len-sizeof(struct palacios_host_dev_host_request_response));
249                     new->data_len=(*r)->data_len;
250                     palacios_free(*r);
251                 }
252                 *r=new;
253                 DEEP_DEBUG_PRINT("palacios: hostdev: reallocated\n");
254                 return 0;
255             }
256         }
257     }
258 }
259
260 static void cycle_request_response(struct palacios_host_device_user *dev)
261 {
262     DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response\n");
263     // wake up user side so that polls fall through
264     wake_up_interruptible(&(dev->user_wait_queue));
265     // put us to sleep until the user side wakes us up
266     while (wait_event_interruptible((dev->host_wait_queue), (dev->waiting==0)) != 0) {}
267
268     DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response - done\n");
269 }
270
271 static void cycle_response_request(struct palacios_host_device_user *dev)
272 {
273     DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request\n");
274     // wake up host side
275     wake_up_interruptible(&(dev->host_wait_queue));
276     DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request - done\n");
277 }
278
279     
280 /*********************************************************************************************
281
282     Interface to user space
283
284  *********************************************************************************************/ 
285
286
287
288 static unsigned int host_dev_poll(struct file * filp, 
289                                   struct poll_table_struct * poll_tb) 
290 {
291
292     struct palacios_host_device_user * dev = filp->private_data;
293     unsigned long f;
294
295     SHALLOW_DEBUG_PRINT("palacios: hostdev: poll\n");
296
297     if (!dev->connected) { 
298         ERROR("palcios: hostdev: poll on unconnected device\n");
299         return -EFAULT;
300     }
301
302     palacios_spinlock_lock_irqsave(&(dev->lock),f);
303
304     if (dev->waiting) { 
305         // Yes, we have a request if you want it!
306         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
307         DEEP_DEBUG_PRINT("palacios: hostdev: poll done immediate\n");
308         return  POLLIN | POLLRDNORM;
309     } 
310
311     // No request yet, so we need to wait for one to show up.
312
313     // register ourselves on the user wait queue
314     poll_wait(filp, &(dev->user_wait_queue), poll_tb);
315
316     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
317
318     DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n");
319     // We will get called again when that queue is woken up
320
321     return 0;
322 }
323
324
325 static int host_dev_release(struct inode * i, struct file * filp) 
326 {
327     struct palacios_host_device_user *dev = filp->private_data;
328     unsigned long f;
329
330     INFO("palacios: user side is closing host device \"%s\"\n",dev->url);
331     
332     palacios_spinlock_lock_irqsave(&(dev->lock), f);
333     dev->connected = 0;
334     palacios_spinlock_unlock_irqrestore(&(dev->lock), f);
335
336     // it is the palacios->host interface's responsibility to ignore
337     // reads/writes until connected is true
338
339     return 0;
340 }
341
342 static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg)
343 {
344     void __user *argp = (void __user *)arg;
345
346     struct palacios_host_device_user *dev = fp->private_data;
347
348     DEEP_DEBUG_PRINT("palacios: hostdev: ioctl %u\n",val);
349     
350
351     if (!dev->connected) { 
352         ERROR("palacios: hostdev: ioctl on unconnected device\n");
353         return -EFAULT;
354     }
355     
356     switch (val) { 
357         case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
358             
359             struct palacios_host_dev_user_op op;
360             
361             if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) { 
362                 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
363                 return -EFAULT;
364             }
365
366             DEEP_DEBUG_PRINT("palacios: hostdev: user request push, type %d\n",op.type);
367             
368             switch (op.type) { 
369                 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
370                     void *temp = palacios_alloc(op.len);
371
372                     DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
373
374                     if (!temp) { 
375                         ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
376                         return -EFAULT;
377                     }
378                     
379                     if (v3_host_dev_read_guest_mem(dev,
380                                                    dev->guestdev,
381                                                    op.gpa,
382                                                    temp,
383                                                    op.len) != op.len) {
384                         ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
385                         palacios_free(temp);
386                         return -EFAULT;
387                     }
388                     
389                     if (copy_to_user(op.data,temp,op.len)) { 
390                         ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
391                         palacios_free(temp);
392                         return -EFAULT;
393                     }
394
395                     palacios_free(temp);
396
397                     return op.len;
398                 }
399                     break;
400                     
401
402                 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
403                     void *temp;
404                     
405                     DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
406
407                     temp = palacios_alloc(op.len);
408
409                     if (!temp) { 
410                         ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
411                         return -EFAULT;
412                     }
413                     
414                     if (copy_from_user(temp,op.data,op.len)) { 
415                         ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
416                         palacios_free(temp);
417                         return -EFAULT;
418                     }
419                     
420                     if (v3_host_dev_write_guest_mem(dev,
421                                                     dev->guestdev,
422                                                     op.gpa,
423                                                     temp,
424                                                     op.len) != op.len) {
425                         ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
426                         palacios_free(temp);
427                         return -EFAULT;
428                     }
429
430                     palacios_free(temp);
431                     
432                     return op.len;
433                 }
434                     break;
435
436                 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
437
438                     DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n");
439
440                     return  v3_host_dev_raise_irq(dev, dev->guestdev, op.irq);
441                 }
442                     break;
443
444                 default:
445                     ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url);
446                     return -EFAULT;
447                     break;
448             }
449         }
450             break;
451
452         case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
453             
454             unsigned long f;
455
456
457             DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
458             
459             palacios_spinlock_lock_irqsave(&(dev->lock),f);
460             
461             if (!(dev->waiting)) { 
462                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
463                 DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n");
464                 schedule();  // avoid livelock for polling user space process  SUSPICOUS
465                 return 0; // no request available now
466             } 
467             
468             if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { 
469                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
470                 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
471                 return -EFAULT; // failed to copy!
472
473             }
474             
475             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
476
477             DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
478
479             return 1; // have request for you
480             
481         }
482             
483             break;
484             
485         case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
486             
487             unsigned long f;
488             
489             palacios_spinlock_lock_irqsave(&(dev->lock),f);
490             
491             DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
492
493             if (!(dev->waiting) || !(dev->req)) { 
494                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
495                 DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
496                 return 0; // no request available now
497             } 
498
499             
500             if (copy_to_user(argp,dev->req,dev->req->data_len)) { 
501                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
502                 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
503                 return -EFAULT; // failed to copy!
504             }
505     
506             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
507
508             DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
509             
510             return 1; // copied request for you
511         }
512             break;
513             
514         case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
515
516             unsigned long f;
517             uint64_t user_datalen;
518             uint64_t old_len;
519             
520             palacios_spinlock_lock_irqsave(&(dev->lock),f);
521             
522             DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
523
524             if (!(dev->waiting)) { 
525                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
526                 ERROR("palacios: hostdev: no matching request for pushed response\n");
527                 return 0; // no request outstanding, so we do not need a response!
528             }
529             
530             if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { 
531                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
532                 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
533                 return -EFAULT; // failed to copy!
534             } 
535
536             if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) { 
537                 // bad user
538                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
539                 ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
540                 return -EFAULT;
541             }
542
543             if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
544                 // not enough room.
545                 // we drop the lock, turn on interrupts, resize, and then retry
546                 DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
547
548                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
549                 
550                 if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
551                     ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
552                     return -EFAULT;
553                 } else {
554                     // reacquire the lock
555                     // There shouldn't be a race here, since there should
556                     // be exactly one user space thread giving us a response for this device
557                     // and it is blocked waiting for us to finish
558                     palacios_spinlock_lock_irqsave(&(dev->lock),f);
559                     DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url);
560                 }
561             }
562
563             //We only copy data_len bytes from user, but we will
564             //overwrite the len field, so we preserve and then restore
565             old_len = dev->resp->len;
566             if (copy_from_user(dev->resp, argp, user_datalen)) { 
567                 dev->resp->len=old_len;
568                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
569                 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
570                 return -EFAULT; // failed to copy!
571             } 
572             dev->resp->len=old_len;
573             
574             DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
575             // now have valid response!
576             dev->waiting=0;
577
578             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
579
580             // wake the palacios side up so that it sees it
581             cycle_response_request(dev);
582
583             return 1; // done
584         }
585             break;
586             
587         default:
588             ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
589             return -EFAULT;
590             break;
591     }
592     
593 }
594
595 static struct file_operations host_dev_fops = {
596     .poll     = host_dev_poll,
597     .release  = host_dev_release,
598     .compat_ioctl = host_dev_ioctl,
599     .unlocked_ioctl = host_dev_ioctl,
600 };
601
602
603
604 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) 
605 {
606     void __user * argp = (void __user *)arg;
607     char url[MAX_URL];
608     struct palacios_host_dev * host_dev = priv_data;
609     struct palacios_host_device_user *dev;
610     unsigned long f1, f2;
611     int i;
612
613
614
615     if (copy_from_user(url, argp, MAX_URL)) {
616         ERROR("copy from user error getting url for host device connect...\n");
617         return -EFAULT;
618     }
619
620     // currently only support user: types:
621     if (strncasecmp(url,"user:",5)) { 
622         ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
623         return -1;
624     }
625     
626     INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
627     
628     // We will scan the list looking for the relevant
629     // URL.  If we don't find it after a while, we give up
630     
631     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
632         palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
633         list_for_each_entry(dev,&(host_dev->devs), node) {
634             if (!strncasecmp(url,dev->url,MAX_URL)) { 
635                 // found it
636                 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
637                 if (dev->connected) { 
638                     ERROR("palacios: device for \"%s\" is already connected!\n",url);
639                     palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
640                     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
641                     return -1;
642                 } else {
643                     dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
644                     if (dev->fd<0) { 
645                         ERROR("palacios: cannot create fd for device \"%s\"\n",url);
646                         palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
647                         palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
648                         return -1;
649                     }
650                     dev->connected=1;
651                     dev->waiting=0;
652                     if (dev->req) { 
653                         palacios_free(dev->req);
654                         dev->req=0;
655                     } 
656                     if (dev->resp) { 
657                         palacios_free(dev->resp);
658                         dev->resp=0;
659                     }
660                     INFO("palacios: connected fd for device \"%s\"\n",url);
661                     palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
662                     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
663                     return dev->fd;
664                 }
665                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
666             }
667         }
668         palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
669         
670         ssleep(RENDEZVOUS_RETRY_SECS);
671     }
672     
673     ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
674     
675     return -1;
676     
677 }
678
679
680
681
682
683
684
685
686 /***************************************************************************************
687
688    Following this is the implementation of the palacios->host interface
689
690 **************************************************************************************/
691
692
693 /* Attempt to rendezvous with the user device if no device is currently connected */
694 static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
695 {
696     unsigned long f;
697     int i;
698
699     if (dev->connected) { 
700         return 0;
701     }
702
703    
704     INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
705
706     // Now wait until we are noticed!
707     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
708         palacios_spinlock_lock_irqsave(&(dev->lock),f);
709         if (dev->connected) { 
710             INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
711             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
712             return 0;
713         }
714         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
715         ssleep(RENDEZVOUS_RETRY_SECS);
716     }
717     
718     ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
719
720     // We stay in the list because a future rendezvous might happen
721     
722     return -1;
723 }
724
725
726 /* Creates the device without rendezvous */
727 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
728                                                      v3_bus_class_t bus,
729                                                      v3_guest_dev_t gdev,
730                                                      void *host_priv_data)
731 {
732     struct v3_guest *guest= (struct v3_guest*)host_priv_data;
733     struct palacios_host_device_user *dev;
734     struct palacios_host_dev * host_dev = NULL;
735     unsigned long f;
736
737     /*
738       I will create the device in the list and then wait
739       for the user side to attach
740     */
741
742     if (guest == NULL) {
743         return 0;
744     }
745     
746
747     host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
748
749     if (host_dev == NULL) {
750         ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
751         return 0;
752     }
753
754
755     if (strncasecmp(url,"user:",5)) { 
756         ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
757         return NULL;
758     }
759
760     // Check to see if a device of this url already exists, which would be ugly
761     palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
762     list_for_each_entry(dev,&(host_dev->devs), node) {
763         if (!strncasecmp(url,dev->url,MAX_URL)) { 
764             // found it
765             palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
766             ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
767             return NULL;
768         }
769     }
770     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
771
772
773     INFO("palacios: creating host device \"%s\"\n",url);
774
775     dev = palacios_alloc(sizeof(struct palacios_host_device_user));
776     
777     if (!dev) { 
778         ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
779         return NULL;
780     }
781
782     memset(dev,0,sizeof(struct palacios_host_device_user));
783     
784     strncpy(dev->url,url,MAX_URL);
785     
786     dev->guestdev = gdev;
787     
788     dev->guest = guest;
789
790     palacios_spinlock_init(&(dev->lock));
791
792     init_waitqueue_head(&(dev->user_wait_queue));
793     init_waitqueue_head(&(dev->host_wait_queue));
794
795     // Insert ourselves into the list
796     palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
797     list_add(&(dev->node),&(host_dev->devs));
798     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
799
800     INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
801
802     return dev;
803
804 }
805
806
807
808 static int palacios_host_dev_close(v3_host_dev_t hostdev)
809 {
810     unsigned long f1, f2;
811
812     struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
813     struct palacios_host_dev * host_dev = NULL;
814
815     INFO("palacios: closing host device \"%s\"\n",dev->url);
816
817     if ((dev == NULL) || (dev->guest == NULL)) {
818         return -1;
819     }
820
821     host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
822
823     
824     if (host_dev == NULL) {
825         return -1;
826     }
827
828     palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
829
830     palacios_spinlock_lock_irqsave(&(dev->lock),f2);
831
832     if (dev->connected) { 
833         dev->connected=0;
834         // After this, any user side request will return -EFAULT
835     }
836
837     list_del(&(dev->node));
838     
839     palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
840     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
841     
842     palacios_spinlock_deinit(&(dev->lock));
843
844     palacios_host_dev_user_free(dev);
845
846     return 0;
847 }
848
849
850
851         
852 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
853                                           uint16_t      port,
854                                           void          *dest,
855                                           uint64_t      len)
856 {
857     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
858     unsigned long f;
859     uint64_t op_len;
860
861     DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
862             
863
864     palacios_spinlock_lock_irqsave(&(dev->lock),f);
865     
866     if (palacios_host_dev_rendezvous(dev)) {
867         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
868         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
869         return 0;
870     }
871
872     if (dev->waiting) { 
873         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
874         ERROR("palacios: guest issued i/o read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
875         return 0;
876     }
877
878     
879     
880     // resize request (no data)
881     if (!palacios_bigenough_reqresp(dev->req,0)) {
882         // not enough room.
883         // we drop the lock, turn on interrupts, resize, and then retry
884         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
885         
886         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
887         
888         if (palacios_resize_reqresp(&(dev->req),0,0)) {
889             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
890             return 0;
891         } else {
892             // reacquire the lock
893             // There shouldn't be a race here since there should not be another
894             // request from palacios until this one finishes
895             palacios_spinlock_lock_irqsave(&(dev->lock),f);
896             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
897         }
898     }
899     
900
901     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
902     dev->req->port=port;
903     dev->req->op_len=len;
904     dev->req->gpa=0;
905     dev->req->conf_addr=0;
906     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
907
908     dev->waiting=1;
909     
910     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
911
912     // hand over to the user space and wait for it to respond
913     cycle_request_response(dev);
914
915     // We're back!   So now we'll hand the response back to Palacios
916
917     palacios_spinlock_lock_irqsave(&(dev->lock),f);
918
919     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
920
921     memcpy(dest,dev->resp->data, op_len);
922     
923     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
924
925     return op_len;
926 }
927
928 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
929                                            void *        gpa,
930                                            void          *dest,
931                                            uint64_t      len)
932 {
933     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
934     unsigned long f;
935     uint64_t op_len;
936
937     DEEP_DEBUG_PRINT("palacios: hostdev: read mem  0x%p\n",gpa);
938
939     palacios_spinlock_lock_irqsave(&(dev->lock),f);
940     
941     if (palacios_host_dev_rendezvous(dev)) {
942         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
943         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
944         return 0;
945     }
946
947     if (dev->waiting) { 
948         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
949         ERROR("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
950         return 0;
951     }
952     
953     // resize request (no data)
954     if (!palacios_bigenough_reqresp(dev->req,0)) {
955         // not enough room.
956         // we drop the lock, turn on interrupts, resize, and then retry
957         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
958         
959         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
960         
961         if (palacios_resize_reqresp(&(dev->req),0,0)) {
962             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
963             return 0;
964         } else {
965             // reacquire the lock
966             // There shouldn't be a race here since there should not be another
967             // request from palacios until this one finishes
968             palacios_spinlock_lock_irqsave(&(dev->lock),f);
969             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
970         }
971     }
972
973     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
974     dev->req->port=0;
975     dev->req->op_len=len;
976     dev->req->gpa=gpa;
977     dev->req->conf_addr=0;
978     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
979
980     dev->waiting=1;
981     
982     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
983
984     // hand over to the user space and wait for it to respond
985     cycle_request_response(dev);
986
987     // We're back!   So now we'll hand the response back to Palacios
988
989     palacios_spinlock_lock_irqsave(&(dev->lock),f);
990
991     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
992
993     memcpy(dest,dev->resp->data, op_len);
994     
995     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
996
997     return op_len;
998 }
999
1000 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
1001                                             uint64_t      offset,
1002                                             void          *dest,
1003                                             uint64_t      len)
1004 {
1005     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1006     unsigned long f;
1007     uint64_t op_len;
1008
1009     DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
1010
1011     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1012     
1013     if (palacios_host_dev_rendezvous(dev)) {
1014         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1015         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1016         return 0;
1017     }
1018
1019     if (dev->waiting) { 
1020         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1021         ERROR("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
1022         return 0;
1023     }
1024     
1025     // resize request (no data)
1026     if (!palacios_bigenough_reqresp(dev->req,0)) {
1027         // not enough room.
1028         // we drop the lock, turn on interrupts, resize, and then retry
1029         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1030         
1031         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1032         
1033         if (palacios_resize_reqresp(&(dev->req),0,0)) {
1034             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1035             return 0;
1036         } else {
1037             // reacquire the lock
1038             // There shouldn't be a race here since there should not be another
1039             // request from palacios until this one finishes
1040             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1041             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1042         }
1043     }
1044
1045     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1046     dev->req->port=0;
1047     dev->req->op_len=len;
1048     dev->req->gpa=0;
1049     dev->req->conf_addr=offset;
1050     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1051
1052     dev->waiting=1;
1053     
1054     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1055
1056     // hand over to the user space and wait for it to respond
1057     cycle_request_response(dev);
1058
1059     // We're back!   So now we'll hand the response back to Palacios
1060
1061     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1062
1063     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1064
1065     memcpy(dest,dev->resp->data, op_len);
1066     
1067     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1068
1069     return op_len;
1070 }
1071
1072
1073 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1074                                            uint16_t      port,
1075                                            void          *src,
1076                                            uint64_t      len)
1077 {
1078     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1079     unsigned long f;
1080     uint64_t op_len;
1081
1082     DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1083
1084     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1085     
1086     if (palacios_host_dev_rendezvous(dev)) {
1087         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1088         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1089         return 0;
1090     }
1091
1092     if (dev->waiting) { 
1093         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1094         ERROR("palacios: guest issued i/o write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
1095         return 0;
1096     }
1097
1098     // resize request 
1099     if (!palacios_bigenough_reqresp(dev->req,len)) {
1100         // not enough room.
1101         // we drop the lock, turn on interrupts, resize, and then retry
1102         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1103         
1104         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1105         
1106         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1107             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1108             return 0;
1109         } else {
1110             // reacquire the lock
1111             // There shouldn't be a race here since there should not be another
1112             // request from palacios until this one finishes
1113             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1114             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1115         }
1116     }
1117
1118     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1119     dev->req->port=port;
1120     dev->req->op_len=len;
1121     dev->req->gpa=0;
1122     dev->req->conf_addr=0;
1123     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1124
1125     memcpy(dev->req->data,src,len);
1126
1127     dev->waiting=1;
1128
1129     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1130    
1131     // hand over to the user space and wait for it to respond
1132     cycle_request_response(dev);
1133
1134     // We're back!   So now we'll hand the response back to Palacios
1135
1136     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1137
1138     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1139
1140     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1141
1142     return op_len;
1143 }
1144
1145
1146 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1147                                             void *        gpa,
1148                                             void          *src,
1149                                             uint64_t      len)
1150 {
1151     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1152     unsigned long f;
1153     uint64_t op_len;
1154
1155     DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1156
1157     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1158     
1159     if (palacios_host_dev_rendezvous(dev)) {
1160         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1161         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1162         return 0;
1163     }
1164
1165     if (dev->waiting) { 
1166         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1167         ERROR("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
1168         return 0;
1169     }
1170     
1171     // resize request 
1172     if (!palacios_bigenough_reqresp(dev->req,len)) {
1173         // not enough room.
1174         // we drop the lock, turn on interrupts, resize, and then retry
1175         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1176         
1177         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1178         
1179         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1180             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1181             return 0;
1182         } else {
1183             // reacquire the lock
1184             // There shouldn't be a race here since there should not be another
1185             // request from palacios until this one finishes
1186             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1187             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1188         }
1189     }
1190
1191     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1192     dev->req->port=0;
1193     dev->req->op_len=len;
1194     dev->req->gpa=gpa;
1195     dev->req->conf_addr=0;
1196     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1197
1198     memcpy(dev->req->data,src,len);
1199
1200     dev->waiting=1;
1201     
1202     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1203
1204     // hand over to the user space and wait for it to respond
1205     cycle_request_response(dev);
1206
1207     // We're back!   So now we'll hand the response back to Palacios
1208
1209     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1210
1211     op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1212
1213     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1214
1215     return op_len;
1216 }
1217
1218
1219
1220
1221 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1222                                              uint64_t      offset,
1223                                              void          *src,
1224                                              uint64_t      len)
1225 {
1226     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1227     unsigned long f;
1228     uint64_t op_len;
1229
1230     DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1231
1232     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1233     
1234     if (palacios_host_dev_rendezvous(dev)) {
1235         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1236         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1237         return 0;
1238     }
1239
1240     if (dev->waiting) { 
1241         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1242         ERROR("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
1243         return 0;
1244     }
1245     
1246     // resize request 
1247     if (!palacios_bigenough_reqresp(dev->req,len)) {
1248         // not enough room.
1249         // we drop the lock, turn on interrupts, resize, and then retry
1250         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1251         
1252         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1253         
1254         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1255             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1256             return 0;
1257         } else {
1258             // reacquire the lock
1259             // There shouldn't be a race here since there should not be another
1260             // request from palacios until this one finishes
1261             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1262             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1263         }
1264     }
1265
1266     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1267     dev->req->port=0;
1268     dev->req->op_len=len;
1269     dev->req->gpa=0;
1270     dev->req->conf_addr=offset;
1271     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1272
1273     memcpy(dev->req->data,src,len);
1274
1275     dev->waiting=1;
1276     
1277     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1278
1279     // hand over to the user space and wait for it to respond
1280     cycle_request_response(dev);
1281
1282     // We're back!   So now we'll hand the response back to Palacios
1283
1284     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1285
1286     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1287
1288     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1289
1290     return op_len;
1291 }
1292  
1293  
1294 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1295 {
1296     // we don't care
1297     return 0;
1298 }
1299  
1300
1301
1302
1303
1304 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1305     .open                       = palacios_host_dev_open_deferred,
1306     .close                      = palacios_host_dev_close,
1307     .read_io                    = palacios_host_dev_read_io,
1308     .write_io                   = palacios_host_dev_write_io,
1309     .read_mem                   = palacios_host_dev_read_mem,
1310     .write_mem                  = palacios_host_dev_write_mem,
1311     .read_config                = palacios_host_dev_read_conf,
1312     .write_config               = palacios_host_dev_write_conf,
1313     .ack_irq                    = palacios_host_dev_ack_irq,
1314 };
1315
1316
1317
1318 static int host_dev_init( void ) {
1319     V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1320     
1321     return 0;
1322 }
1323
1324
1325 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1326     struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1327
1328     if (!host_dev) { 
1329         ERROR("palacios: failed to do guest_init for host device\n");
1330         return -1;
1331     }
1332     
1333     
1334     INIT_LIST_HEAD(&(host_dev->devs));
1335     palacios_spinlock_init(&(host_dev->lock));
1336
1337     *vm_data = host_dev;
1338
1339
1340     add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1341
1342     return 0;
1343 }
1344
1345
1346 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1347
1348     struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1349     palacios_spinlock_deinit(&(host_dev->lock));
1350     palacios_free(host_dev);
1351     return 0;
1352 }
1353
1354
1355
1356
1357 static struct linux_ext host_dev_ext = {
1358     .name = "HOST_DEVICE_INTERFACE",
1359     .init = host_dev_init,
1360     .deinit = NULL,
1361     .guest_init = host_dev_guest_init,
1362     .guest_deinit = host_dev_guest_deinit
1363 };
1364
1365
1366 register_extension(&host_dev_ext);