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.


680d7537515f90192a36fff067af73d8c95a10c0
[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
305     // register ourselves on the user wait queue
306     poll_wait(filp, &(dev->user_wait_queue), poll_tb);
307
308     if (dev->waiting) { 
309         // Yes, we have a request if you want it!
310         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
311         DEEP_DEBUG_PRINT("palacios: hostdev: poll done immediate\n");
312         return  POLLIN | POLLRDNORM;
313     } 
314
315     // No request yet, so we need to wait for one to show up.
316
317     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
318
319     DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n");
320     // We will get called again when that queue is woken up
321
322     return 0;
323 }
324
325
326 static int host_dev_release(struct inode * i, struct file * filp) 
327 {
328     struct palacios_host_device_user *dev = filp->private_data;
329     unsigned long f;
330
331     INFO("palacios: user side is closing host device \"%s\"\n",dev->url);
332     
333     palacios_spinlock_lock_irqsave(&(dev->lock), f);
334     dev->connected = 0;
335     palacios_spinlock_unlock_irqrestore(&(dev->lock), f);
336
337     // it is the palacios->host interface's responsibility to ignore
338     // reads/writes until connected is true
339
340     return 0;
341 }
342
343 static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg)
344 {
345     void __user *argp = (void __user *)arg;
346
347     struct palacios_host_device_user *dev = fp->private_data;
348
349     DEEP_DEBUG_PRINT("palacios: hostdev: ioctl %u\n",val);
350     
351
352     if (!dev->connected) { 
353         ERROR("palacios: hostdev: ioctl on unconnected device\n");
354         return -EFAULT;
355     }
356     
357     switch (val) { 
358         case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
359             
360             struct palacios_host_dev_user_op op;
361             
362             if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) { 
363                 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
364                 return -EFAULT;
365             }
366
367             DEEP_DEBUG_PRINT("palacios: hostdev: user request push, type %d\n",op.type);
368             
369             switch (op.type) { 
370                 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
371                     void *temp = palacios_alloc(op.len);
372
373                     DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
374
375                     if (!temp) { 
376                         ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
377                         return -EFAULT;
378                     }
379                     
380                     if (v3_host_dev_read_guest_mem(dev,
381                                                    dev->guestdev,
382                                                    op.gpa,
383                                                    temp,
384                                                    op.len) != op.len) {
385                         ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
386                         palacios_free(temp);
387                         return -EFAULT;
388                     }
389                     
390                     if (copy_to_user(op.data,temp,op.len)) { 
391                         ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
392                         palacios_free(temp);
393                         return -EFAULT;
394                     }
395
396                     palacios_free(temp);
397
398                     return op.len;
399                 }
400                     break;
401                     
402
403                 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
404                     void *temp;
405                     
406                     DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
407
408                     temp = palacios_alloc(op.len);
409
410                     if (!temp) { 
411                         ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
412                         return -EFAULT;
413                     }
414                     
415                     if (copy_from_user(temp,op.data,op.len)) { 
416                         ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
417                         palacios_free(temp);
418                         return -EFAULT;
419                     }
420                     
421                     if (v3_host_dev_write_guest_mem(dev,
422                                                     dev->guestdev,
423                                                     op.gpa,
424                                                     temp,
425                                                     op.len) != op.len) {
426                         ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
427                         palacios_free(temp);
428                         return -EFAULT;
429                     }
430
431                     palacios_free(temp);
432                     
433                     return op.len;
434                 }
435                     break;
436
437                 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
438
439                     DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n");
440
441                     return  v3_host_dev_raise_irq(dev, dev->guestdev, op.irq);
442                 }
443                     break;
444
445                 default:
446                     ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url);
447                     return -EFAULT;
448                     break;
449             }
450         }
451             break;
452
453         case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
454             
455             unsigned long f;
456
457
458             DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
459             
460             palacios_spinlock_lock_irqsave(&(dev->lock),f);
461             
462             if (!(dev->waiting)) { 
463                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
464                 DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n");
465                 schedule();  // avoid livelock for polling user space process  SUSPICOUS
466                 return 0; // no request available now
467             } 
468             
469             if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { 
470                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
471                 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
472                 return -EFAULT; // failed to copy!
473
474             }
475             
476             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
477
478             DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
479
480             return 1; // have request for you
481             
482         }
483             
484             break;
485             
486         case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
487             
488             unsigned long f;
489             
490             palacios_spinlock_lock_irqsave(&(dev->lock),f);
491             
492             DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
493
494             if (!(dev->waiting) || !(dev->req)) { 
495                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
496                 DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
497                 return 0; // no request available now
498             } 
499
500             
501             if (copy_to_user(argp,dev->req,dev->req->data_len)) { 
502                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
503                 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
504                 return -EFAULT; // failed to copy!
505             }
506     
507             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
508
509             DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
510             
511             return 1; // copied request for you
512         }
513             break;
514             
515         case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
516
517             unsigned long f;
518             uint64_t user_datalen;
519             uint64_t old_len;
520             
521             palacios_spinlock_lock_irqsave(&(dev->lock),f);
522             
523             DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
524
525             if (!(dev->waiting)) { 
526                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
527                 ERROR("palacios: hostdev: no matching request for pushed response\n");
528                 return 0; // no request outstanding, so we do not need a response!
529             }
530             
531             if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { 
532                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
533                 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
534                 return -EFAULT; // failed to copy!
535             } 
536
537             if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) { 
538                 // bad user
539                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
540                 ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
541                 return -EFAULT;
542             }
543
544             if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
545                 // not enough room.
546                 // we drop the lock, turn on interrupts, resize, and then retry
547                 DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
548
549                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
550                 
551                 if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
552                     ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
553                     return -EFAULT;
554                 } else {
555                     // reacquire the lock
556                     // There shouldn't be a race here, since there should
557                     // be exactly one user space thread giving us a response for this device
558                     // and it is blocked waiting for us to finish
559                     palacios_spinlock_lock_irqsave(&(dev->lock),f);
560                     DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url);
561                 }
562             }
563
564             //We only copy data_len bytes from user, but we will
565             //overwrite the len field, so we preserve and then restore
566             old_len = dev->resp->len;
567             if (copy_from_user(dev->resp, argp, user_datalen)) { 
568                 dev->resp->len=old_len;
569                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
570                 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
571                 return -EFAULT; // failed to copy!
572             } 
573             dev->resp->len=old_len;
574             
575             DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
576             // now have valid response!
577             dev->waiting=0;
578
579             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
580
581             // wake the palacios side up so that it sees it
582             cycle_response_request(dev);
583
584             return 1; // done
585         }
586             break;
587             
588         default:
589             ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
590             return -EFAULT;
591             break;
592     }
593     
594 }
595
596 static struct file_operations host_dev_fops = {
597     .poll     = host_dev_poll,
598     .release  = host_dev_release,
599     .compat_ioctl = host_dev_ioctl,
600     .unlocked_ioctl = host_dev_ioctl,
601 };
602
603
604
605 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) 
606 {
607     void __user * argp = (void __user *)arg;
608     char url[MAX_URL];
609     struct palacios_host_dev * host_dev = priv_data;
610     struct palacios_host_device_user *dev;
611     unsigned long f1, f2;
612     int i;
613
614
615
616     if (copy_from_user(url, argp, MAX_URL)) {
617         ERROR("copy from user error getting url for host device connect...\n");
618         return -EFAULT;
619     }
620
621     // currently only support user: types:
622     if (strncasecmp(url,"user:",5)) { 
623         ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
624         return -1;
625     }
626     
627     INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
628     
629     // We will scan the list looking for the relevant
630     // URL.  If we don't find it after a while, we give up
631     
632     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
633         palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
634         list_for_each_entry(dev,&(host_dev->devs), node) {
635             if (!strncasecmp(url,dev->url,MAX_URL)) { 
636                 // found it
637                 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
638                 if (dev->connected) { 
639                     ERROR("palacios: device for \"%s\" is already connected!\n",url);
640                     palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
641                     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
642                     return -1;
643                 } else {
644                     dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
645                     if (dev->fd<0) { 
646                         ERROR("palacios: cannot create fd for device \"%s\"\n",url);
647                         palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
648                         palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
649                         return -1;
650                     }
651                     dev->connected=1;
652                     dev->waiting=0;
653                     if (dev->req) { 
654                         palacios_free(dev->req);
655                         dev->req=0;
656                     } 
657                     if (dev->resp) { 
658                         palacios_free(dev->resp);
659                         dev->resp=0;
660                     }
661                     INFO("palacios: connected fd for device \"%s\"\n",url);
662                     palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
663                     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
664                     return dev->fd;
665                 }
666                 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
667             }
668         }
669         palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
670         
671         ssleep(RENDEZVOUS_RETRY_SECS);
672     }
673     
674     ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
675     
676     return -1;
677     
678 }
679
680
681
682
683
684
685
686
687 /***************************************************************************************
688
689    Following this is the implementation of the palacios->host interface
690
691 **************************************************************************************/
692
693
694 /* Attempt to rendezvous with the user device if no device is currently connected */
695 static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
696 {
697     unsigned long f;
698     int i;
699
700     if (dev->connected) { 
701         return 0;
702     }
703
704    
705     INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
706
707     // Now wait until we are noticed!
708     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
709         palacios_spinlock_lock_irqsave(&(dev->lock),f);
710         if (dev->connected) { 
711             INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
712             palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
713             return 0;
714         }
715         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
716         ssleep(RENDEZVOUS_RETRY_SECS);
717     }
718     
719     ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
720
721     // We stay in the list because a future rendezvous might happen
722     
723     return -1;
724 }
725
726
727 /* Creates the device without rendezvous */
728 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
729                                                      v3_bus_class_t bus,
730                                                      v3_guest_dev_t gdev,
731                                                      void *host_priv_data)
732 {
733     struct v3_guest *guest= (struct v3_guest*)host_priv_data;
734     struct palacios_host_device_user *dev;
735     struct palacios_host_dev * host_dev = NULL;
736     unsigned long f;
737
738     /*
739       I will create the device in the list and then wait
740       for the user side to attach
741     */
742
743     if (guest == NULL) {
744         return 0;
745     }
746     
747
748     host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
749
750     if (host_dev == NULL) {
751         ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
752         return 0;
753     }
754
755
756     if (strncasecmp(url,"user:",5)) { 
757         ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
758         return NULL;
759     }
760
761     // Check to see if a device of this url already exists, which would be ugly
762     palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
763     list_for_each_entry(dev,&(host_dev->devs), node) {
764         if (!strncasecmp(url,dev->url,MAX_URL)) { 
765             // found it
766             palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
767             ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
768             return NULL;
769         }
770     }
771     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
772
773
774     INFO("palacios: creating host device \"%s\"\n",url);
775
776     dev = palacios_alloc(sizeof(struct palacios_host_device_user));
777     
778     if (!dev) { 
779         ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
780         return NULL;
781     }
782
783     memset(dev,0,sizeof(struct palacios_host_device_user));
784     
785     strncpy(dev->url,url,MAX_URL);
786     
787     dev->guestdev = gdev;
788     
789     dev->guest = guest;
790
791     palacios_spinlock_init(&(dev->lock));
792
793     init_waitqueue_head(&(dev->user_wait_queue));
794     init_waitqueue_head(&(dev->host_wait_queue));
795
796     // Insert ourselves into the list
797     palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
798     list_add(&(dev->node),&(host_dev->devs));
799     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
800
801     INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
802
803     return dev;
804
805 }
806
807
808
809 static int palacios_host_dev_close(v3_host_dev_t hostdev)
810 {
811     unsigned long f1, f2;
812
813     struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
814     struct palacios_host_dev * host_dev = NULL;
815
816     INFO("palacios: closing host device \"%s\"\n",dev->url);
817
818     if ((dev == NULL) || (dev->guest == NULL)) {
819         return -1;
820     }
821
822     host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
823
824     
825     if (host_dev == NULL) {
826         return -1;
827     }
828
829     palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
830
831     palacios_spinlock_lock_irqsave(&(dev->lock),f2);
832
833     if (dev->connected) { 
834         dev->connected=0;
835         // After this, any user side request will return -EFAULT
836     }
837
838     list_del(&(dev->node));
839     
840     palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
841     palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
842     
843     palacios_spinlock_deinit(&(dev->lock));
844
845     palacios_host_dev_user_free(dev);
846
847     return 0;
848 }
849
850
851
852         
853 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
854                                           uint16_t      port,
855                                           void          *dest,
856                                           uint64_t      len)
857 {
858     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
859     unsigned long f;
860     uint64_t op_len;
861
862     DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
863             
864
865     palacios_spinlock_lock_irqsave(&(dev->lock),f);
866     
867     if (palacios_host_dev_rendezvous(dev)) {
868         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
869         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
870         return 0;
871     }
872
873     if (dev->waiting) { 
874         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
875         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);
876         return 0;
877     }
878
879     
880     
881     // resize request (no data)
882     if (!palacios_bigenough_reqresp(dev->req,0)) {
883         // not enough room.
884         // we drop the lock, turn on interrupts, resize, and then retry
885         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
886         
887         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
888         
889         if (palacios_resize_reqresp(&(dev->req),0,0)) {
890             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
891             return 0;
892         } else {
893             // reacquire the lock
894             // There shouldn't be a race here since there should not be another
895             // request from palacios until this one finishes
896             palacios_spinlock_lock_irqsave(&(dev->lock),f);
897             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
898         }
899     }
900     
901
902     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
903     dev->req->port=port;
904     dev->req->op_len=len;
905     dev->req->gpa=0;
906     dev->req->conf_addr=0;
907     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
908
909     dev->waiting=1;
910     
911     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
912
913     // hand over to the user space and wait for it to respond
914     cycle_request_response(dev);
915
916     // We're back!   So now we'll hand the response back to Palacios
917
918     palacios_spinlock_lock_irqsave(&(dev->lock),f);
919
920     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
921
922     memcpy(dest,dev->resp->data, op_len);
923     
924     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
925
926     return op_len;
927 }
928
929 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
930                                            void *        gpa,
931                                            void          *dest,
932                                            uint64_t      len)
933 {
934     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
935     unsigned long f;
936     uint64_t op_len;
937
938     DEEP_DEBUG_PRINT("palacios: hostdev: read mem  0x%p\n",gpa);
939
940     palacios_spinlock_lock_irqsave(&(dev->lock),f);
941     
942     if (palacios_host_dev_rendezvous(dev)) {
943         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
944         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
945         return 0;
946     }
947
948     if (dev->waiting) { 
949         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
950         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);
951         return 0;
952     }
953     
954     // resize request (no data)
955     if (!palacios_bigenough_reqresp(dev->req,0)) {
956         // not enough room.
957         // we drop the lock, turn on interrupts, resize, and then retry
958         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
959         
960         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
961         
962         if (palacios_resize_reqresp(&(dev->req),0,0)) {
963             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
964             return 0;
965         } else {
966             // reacquire the lock
967             // There shouldn't be a race here since there should not be another
968             // request from palacios until this one finishes
969             palacios_spinlock_lock_irqsave(&(dev->lock),f);
970             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
971         }
972     }
973
974     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
975     dev->req->port=0;
976     dev->req->op_len=len;
977     dev->req->gpa=gpa;
978     dev->req->conf_addr=0;
979     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
980
981     dev->waiting=1;
982     
983     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
984
985     // hand over to the user space and wait for it to respond
986     cycle_request_response(dev);
987
988     // We're back!   So now we'll hand the response back to Palacios
989
990     palacios_spinlock_lock_irqsave(&(dev->lock),f);
991
992     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
993
994     memcpy(dest,dev->resp->data, op_len);
995     
996     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
997
998     return op_len;
999 }
1000
1001 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
1002                                             uint64_t      offset,
1003                                             void          *dest,
1004                                             uint64_t      len)
1005 {
1006     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1007     unsigned long f;
1008     uint64_t op_len;
1009
1010     DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
1011
1012     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1013     
1014     if (palacios_host_dev_rendezvous(dev)) {
1015         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1016         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1017         return 0;
1018     }
1019
1020     if (dev->waiting) { 
1021         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1022         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);
1023         return 0;
1024     }
1025     
1026     // resize request (no data)
1027     if (!palacios_bigenough_reqresp(dev->req,0)) {
1028         // not enough room.
1029         // we drop the lock, turn on interrupts, resize, and then retry
1030         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1031         
1032         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1033         
1034         if (palacios_resize_reqresp(&(dev->req),0,0)) {
1035             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1036             return 0;
1037         } else {
1038             // reacquire the lock
1039             // There shouldn't be a race here since there should not be another
1040             // request from palacios until this one finishes
1041             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1042             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1043         }
1044     }
1045
1046     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1047     dev->req->port=0;
1048     dev->req->op_len=len;
1049     dev->req->gpa=0;
1050     dev->req->conf_addr=offset;
1051     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1052
1053     dev->waiting=1;
1054     
1055     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1056
1057     // hand over to the user space and wait for it to respond
1058     cycle_request_response(dev);
1059
1060     // We're back!   So now we'll hand the response back to Palacios
1061
1062     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1063
1064     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1065
1066     memcpy(dest,dev->resp->data, op_len);
1067     
1068     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1069
1070     return op_len;
1071 }
1072
1073
1074 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1075                                            uint16_t      port,
1076                                            void          *src,
1077                                            uint64_t      len)
1078 {
1079     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1080     unsigned long f;
1081     uint64_t op_len;
1082
1083     DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1084
1085     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1086     
1087     if (palacios_host_dev_rendezvous(dev)) {
1088         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1089         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1090         return 0;
1091     }
1092
1093     if (dev->waiting) { 
1094         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1095         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);
1096         return 0;
1097     }
1098
1099     // resize request 
1100     if (!palacios_bigenough_reqresp(dev->req,len)) {
1101         // not enough room.
1102         // we drop the lock, turn on interrupts, resize, and then retry
1103         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1104         
1105         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1106         
1107         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1108             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1109             return 0;
1110         } else {
1111             // reacquire the lock
1112             // There shouldn't be a race here since there should not be another
1113             // request from palacios until this one finishes
1114             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1115             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1116         }
1117     }
1118
1119     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1120     dev->req->port=port;
1121     dev->req->op_len=len;
1122     dev->req->gpa=0;
1123     dev->req->conf_addr=0;
1124     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1125
1126     memcpy(dev->req->data,src,len);
1127
1128     dev->waiting=1;
1129
1130     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1131    
1132     // hand over to the user space and wait for it to respond
1133     cycle_request_response(dev);
1134
1135     // We're back!   So now we'll hand the response back to Palacios
1136
1137     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1138
1139     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1140
1141     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1142
1143     return op_len;
1144 }
1145
1146
1147 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1148                                             void *        gpa,
1149                                             void          *src,
1150                                             uint64_t      len)
1151 {
1152     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1153     unsigned long f;
1154     uint64_t op_len;
1155
1156     DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1157
1158     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1159     
1160     if (palacios_host_dev_rendezvous(dev)) {
1161         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1162         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1163         return 0;
1164     }
1165
1166     if (dev->waiting) { 
1167         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1168         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);
1169         return 0;
1170     }
1171     
1172     // resize request 
1173     if (!palacios_bigenough_reqresp(dev->req,len)) {
1174         // not enough room.
1175         // we drop the lock, turn on interrupts, resize, and then retry
1176         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1177         
1178         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1179         
1180         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1181             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1182             return 0;
1183         } else {
1184             // reacquire the lock
1185             // There shouldn't be a race here since there should not be another
1186             // request from palacios until this one finishes
1187             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1188             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1189         }
1190     }
1191
1192     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1193     dev->req->port=0;
1194     dev->req->op_len=len;
1195     dev->req->gpa=gpa;
1196     dev->req->conf_addr=0;
1197     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1198
1199     memcpy(dev->req->data,src,len);
1200
1201     dev->waiting=1;
1202     
1203     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1204
1205     // hand over to the user space and wait for it to respond
1206     cycle_request_response(dev);
1207
1208     // We're back!   So now we'll hand the response back to Palacios
1209
1210     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1211
1212     op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1213
1214     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1215
1216     return op_len;
1217 }
1218
1219
1220
1221
1222 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1223                                              uint64_t      offset,
1224                                              void          *src,
1225                                              uint64_t      len)
1226 {
1227     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1228     unsigned long f;
1229     uint64_t op_len;
1230
1231     DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1232
1233     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1234     
1235     if (palacios_host_dev_rendezvous(dev)) {
1236         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1237         ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1238         return 0;
1239     }
1240
1241     if (dev->waiting) { 
1242         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1243         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);
1244         return 0;
1245     }
1246     
1247     // resize request 
1248     if (!palacios_bigenough_reqresp(dev->req,len)) {
1249         // not enough room.
1250         // we drop the lock, turn on interrupts, resize, and then retry
1251         DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1252         
1253         palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1254         
1255         if (palacios_resize_reqresp(&(dev->req),len,0)) {
1256             ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1257             return 0;
1258         } else {
1259             // reacquire the lock
1260             // There shouldn't be a race here since there should not be another
1261             // request from palacios until this one finishes
1262             palacios_spinlock_lock_irqsave(&(dev->lock),f);
1263             DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1264         }
1265     }
1266
1267     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1268     dev->req->port=0;
1269     dev->req->op_len=len;
1270     dev->req->gpa=0;
1271     dev->req->conf_addr=offset;
1272     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1273
1274     memcpy(dev->req->data,src,len);
1275
1276     dev->waiting=1;
1277     
1278     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1279
1280     // hand over to the user space and wait for it to respond
1281     cycle_request_response(dev);
1282
1283     // We're back!   So now we'll hand the response back to Palacios
1284
1285     palacios_spinlock_lock_irqsave(&(dev->lock),f);
1286
1287     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1288
1289     palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1290
1291     return op_len;
1292 }
1293  
1294  
1295 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1296 {
1297     // we don't care
1298     return 0;
1299 }
1300  
1301
1302
1303
1304
1305 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1306     .open                       = palacios_host_dev_open_deferred,
1307     .close                      = palacios_host_dev_close,
1308     .read_io                    = palacios_host_dev_read_io,
1309     .write_io                   = palacios_host_dev_write_io,
1310     .read_mem                   = palacios_host_dev_read_mem,
1311     .write_mem                  = palacios_host_dev_write_mem,
1312     .read_config                = palacios_host_dev_read_conf,
1313     .write_config               = palacios_host_dev_write_conf,
1314     .ack_irq                    = palacios_host_dev_ack_irq,
1315 };
1316
1317
1318
1319 static int host_dev_init( void ) {
1320     V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1321     
1322     return 0;
1323 }
1324
1325
1326 static int host_dev_deinit(void) { 
1327     // nothing to do
1328     return 0;
1329 }
1330
1331 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1332     struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1333
1334     if (!host_dev) { 
1335         ERROR("palacios: failed to do guest_init for host device\n");
1336         return -1;
1337     }
1338     
1339     
1340     INIT_LIST_HEAD(&(host_dev->devs));
1341     palacios_spinlock_init(&(host_dev->lock));
1342
1343     *vm_data = host_dev;
1344
1345
1346     add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1347
1348     return 0;
1349 }
1350
1351
1352 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1353
1354     struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1355     remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT);
1356     palacios_spinlock_deinit(&(host_dev->lock));
1357     palacios_free(host_dev);
1358     return 0;
1359 }
1360
1361
1362
1363
1364 static struct linux_ext host_dev_ext = {
1365     .name = "HOST_DEVICE_INTERFACE",
1366     .init = host_dev_init,
1367     .deinit = host_dev_deinit,
1368     .guest_init = host_dev_guest_init,
1369     .guest_deinit = host_dev_guest_deinit
1370 };
1371
1372
1373 register_extension(&host_dev_ext);