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 checking framework and cleanup of linux module code to use palacios interfaces...
[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_host_dev_user_free(dev);
843
844     return 0;
845 }
846
847
848
849         
850 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
851                                           uint16_t      port,
852                                           void          *dest,
853                                           uint64_t      len)
854 {
855     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
856     unsigned long f;
857     uint64_t op_len;
858
859     DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
860             
861
862     palacios_spinlock_lock_irqsave(&(dev->lock),f);
863     
864     if (palacios_host_dev_rendezvous(dev)) {
865         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
866         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
867         return 0;
868     }
869
870     if (dev->waiting) { 
871         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
872         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);
873         return 0;
874     }
875
876     
877     
878     // resize request (no data)
879     if (!palacios_bigenough_reqresp(dev->req,0)) {
880         // not enough room.
881         // we drop the lock, turn on interrupts, resize, and then retry
882         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
883         
884         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
885         
886         if (palacios_resize_reqresp(&(dev->req),0,0)) {
887             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
888             return 0;
889         } else {
890             // reacquire the lock
891             // There shouldn't be a race here since there should not be another
892             // request from palacios until this one finishes
893             palacios_spinlock_lock_irqsave(&(dev->lock),f);
894             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
895         }
896     }
897     
898
899     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
900     dev->req->port=port;
901     dev->req->op_len=len;
902     dev->req->gpa=0;
903     dev->req->conf_addr=0;
904     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
905
906     dev->waiting=1;
907     
908     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
909
910     // hand over to the user space and wait for it to respond
911     cycle_request_response(dev);
912
913     // We're back!   So now we'll hand the response back to Palacios
914
915     palacios_spinlock_lock_irqsave(&(dev->lock),f);
916
917     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
918
919     memcpy(dest,dev->resp->data, op_len);
920     
921     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
922
923     return op_len;
924 }
925
926 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
927                                            void *        gpa,
928                                            void          *dest,
929                                            uint64_t      len)
930 {
931     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
932     unsigned long f;
933     uint64_t op_len;
934
935     DEEP_DEBUG_PRINT("palacios: hostdev: read mem  0x%p\n",gpa);
936
937     palacios_spinlock_lock_irqsave(&(dev->lock),f);
938     
939     if (palacios_host_dev_rendezvous(dev)) {
940         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
941         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
942         return 0;
943     }
944
945     if (dev->waiting) { 
946         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
947         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);
948         return 0;
949     }
950     
951     // resize request (no data)
952     if (!palacios_bigenough_reqresp(dev->req,0)) {
953         // not enough room.
954         // we drop the lock, turn on interrupts, resize, and then retry
955         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
956         
957         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
958         
959         if (palacios_resize_reqresp(&(dev->req),0,0)) {
960             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
961             return 0;
962         } else {
963             // reacquire the lock
964             // There shouldn't be a race here since there should not be another
965             // request from palacios until this one finishes
966             palacios_spinlock_lock_irqsave(&(dev->lock),f);
967             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
968         }
969     }
970
971     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
972     dev->req->port=0;
973     dev->req->op_len=len;
974     dev->req->gpa=gpa;
975     dev->req->conf_addr=0;
976     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
977
978     dev->waiting=1;
979     
980     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
981
982     // hand over to the user space and wait for it to respond
983     cycle_request_response(dev);
984
985     // We're back!   So now we'll hand the response back to Palacios
986
987     palacios_spinlock_lock_irqsave(&(dev->lock),f);
988
989     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
990
991     memcpy(dest,dev->resp->data, op_len);
992     
993     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
994
995     return op_len;
996 }
997
998 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
999                                             uint64_t      offset,
1000                                             void          *dest,
1001                                             uint64_t      len)
1002 {
1003     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1004     unsigned long f;
1005     uint64_t op_len;
1006
1007     DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
1008
1009     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1010     
1011     if (palacios_host_dev_rendezvous(dev)) {
1012         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1013         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1014         return 0;
1015     }
1016
1017     if (dev->waiting) { 
1018         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1019         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);
1020         return 0;
1021     }
1022     
1023     // resize request (no data)
1024     if (!palacios_bigenough_reqresp(dev->req,0)) {
1025         // not enough room.
1026         // we drop the lock, turn on interrupts, resize, and then retry
1027         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1028         
1029         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1030         
1031         if (palacios_resize_reqresp(&(dev->req),0,0)) {
1032             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1033             return 0;
1034         } else {
1035             // reacquire the lock
1036             // There shouldn't be a race here since there should not be another
1037             // request from palacios until this one finishes
1038             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1039             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1040         }
1041     }
1042
1043     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1044     dev->req->port=0;
1045     dev->req->op_len=len;
1046     dev->req->gpa=0;
1047     dev->req->conf_addr=offset;
1048     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1049
1050     dev->waiting=1;
1051     
1052     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1053
1054     // hand over to the user space and wait for it to respond
1055     cycle_request_response(dev);
1056
1057     // We're back!   So now we'll hand the response back to Palacios
1058
1059     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1060
1061     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1062
1063     memcpy(dest,dev->resp->data, op_len);
1064     
1065     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1066
1067     return op_len;
1068 }
1069
1070
1071 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1072                                            uint16_t      port,
1073                                            void          *src,
1074                                            uint64_t      len)
1075 {
1076     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1077     unsigned long f;
1078     uint64_t op_len;
1079
1080     DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1081
1082     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1083     
1084     if (palacios_host_dev_rendezvous(dev)) {
1085         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1086         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1087         return 0;
1088     }
1089
1090     if (dev->waiting) { 
1091         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1092         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);
1093         return 0;
1094     }
1095
1096     // resize request 
1097     if (!palacios_bigenough_reqresp(dev->req,len)) {
1098         // not enough room.
1099         // we drop the lock, turn on interrupts, resize, and then retry
1100         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1101         
1102         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1103         
1104         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1105             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1106             return 0;
1107         } else {
1108             // reacquire the lock
1109             // There shouldn't be a race here since there should not be another
1110             // request from palacios until this one finishes
1111             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1112             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1113         }
1114     }
1115
1116     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1117     dev->req->port=port;
1118     dev->req->op_len=len;
1119     dev->req->gpa=0;
1120     dev->req->conf_addr=0;
1121     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1122
1123     memcpy(dev->req->data,src,len);
1124
1125     dev->waiting=1;
1126
1127     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1128    
1129     // hand over to the user space and wait for it to respond
1130     cycle_request_response(dev);
1131
1132     // We're back!   So now we'll hand the response back to Palacios
1133
1134     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1135
1136     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1137
1138     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1139
1140     return op_len;
1141 }
1142
1143
1144 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1145                                             void *        gpa,
1146                                             void          *src,
1147                                             uint64_t      len)
1148 {
1149     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1150     unsigned long f;
1151     uint64_t op_len;
1152
1153     DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1154
1155     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1156     
1157     if (palacios_host_dev_rendezvous(dev)) {
1158         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1159         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1160         return 0;
1161     }
1162
1163     if (dev->waiting) { 
1164         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1165         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);
1166         return 0;
1167     }
1168     
1169     // resize request 
1170     if (!palacios_bigenough_reqresp(dev->req,len)) {
1171         // not enough room.
1172         // we drop the lock, turn on interrupts, resize, and then retry
1173         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1174         
1175         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1176         
1177         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1178             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1179             return 0;
1180         } else {
1181             // reacquire the lock
1182             // There shouldn't be a race here since there should not be another
1183             // request from palacios until this one finishes
1184             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1185             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1186         }
1187     }
1188
1189     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1190     dev->req->port=0;
1191     dev->req->op_len=len;
1192     dev->req->gpa=gpa;
1193     dev->req->conf_addr=0;
1194     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1195
1196     memcpy(dev->req->data,src,len);
1197
1198     dev->waiting=1;
1199     
1200     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1201
1202     // hand over to the user space and wait for it to respond
1203     cycle_request_response(dev);
1204
1205     // We're back!   So now we'll hand the response back to Palacios
1206
1207     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1208
1209     op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1210
1211     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1212
1213     return op_len;
1214 }
1215
1216
1217
1218
1219 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1220                                              uint64_t      offset,
1221                                              void          *src,
1222                                              uint64_t      len)
1223 {
1224     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1225     unsigned long f;
1226     uint64_t op_len;
1227
1228     DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1229
1230     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1231     
1232     if (palacios_host_dev_rendezvous(dev)) {
1233         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1234         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1235         return 0;
1236     }
1237
1238     if (dev->waiting) { 
1239         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1240         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);
1241         return 0;
1242     }
1243     
1244     // resize request 
1245     if (!palacios_bigenough_reqresp(dev->req,len)) {
1246         // not enough room.
1247         // we drop the lock, turn on interrupts, resize, and then retry
1248         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1249         
1250         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1251         
1252         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1253             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1254             return 0;
1255         } else {
1256             // reacquire the lock
1257             // There shouldn't be a race here since there should not be another
1258             // request from palacios until this one finishes
1259             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1260             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1261         }
1262     }
1263
1264     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1265     dev->req->port=0;
1266     dev->req->op_len=len;
1267     dev->req->gpa=0;
1268     dev->req->conf_addr=offset;
1269     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1270
1271     memcpy(dev->req->data,src,len);
1272
1273     dev->waiting=1;
1274     
1275     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1276
1277     // hand over to the user space and wait for it to respond
1278     cycle_request_response(dev);
1279
1280     // We're back!   So now we'll hand the response back to Palacios
1281
1282     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1283
1284     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1285
1286     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1287
1288     return op_len;
1289 }
1290  
1291  
1292 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1293 {
1294     // we don't care
1295     return 0;
1296 }
1297  
1298
1299
1300
1301
1302 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1303     .open                       = palacios_host_dev_open_deferred,
1304     .close                      = palacios_host_dev_close,
1305     .read_io                    = palacios_host_dev_read_io,
1306     .write_io                   = palacios_host_dev_write_io,
1307     .read_mem                   = palacios_host_dev_read_mem,
1308     .write_mem                  = palacios_host_dev_write_mem,
1309     .read_config                = palacios_host_dev_read_conf,
1310     .write_config               = palacios_host_dev_write_conf,
1311     .ack_irq                    = palacios_host_dev_ack_irq,
1312 };
1313
1314
1315
1316 static int host_dev_init( void ) {
1317     V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1318     
1319     return 0;
1320 }
1321
1322
1323 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1324     struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1325
1326     if (!host_dev) { 
1327         ERROR("palacios: failed to do guest_init for host device\n");
1328         return -1;
1329     }
1330     
1331     
1332     INIT_LIST_HEAD(&(host_dev->devs));
1333     palacios_spinlock_init(&(host_dev->lock));
1334
1335     *vm_data = host_dev;
1336
1337
1338     add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1339
1340     return 0;
1341 }
1342
1343
1344 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1345
1346     palacios_free(vm_data);
1347     return 0;
1348 }
1349
1350
1351
1352
1353 static struct linux_ext host_dev_ext = {
1354     .name = "HOST_DEVICE_INTERFACE",
1355     .init = host_dev_init,
1356     .deinit = NULL,
1357     .guest_init = host_dev_guest_init,
1358     .guest_deinit = host_dev_guest_deinit
1359 };
1360
1361
1362 register_extension(&host_dev_ext);