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.


warning fix
[palacios.git] / linux_module / palacios-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 "palacios-host-dev.h"
21 #include "palacios-host-dev-user.h"
22
23
24
25 /*
26   There are two things in this file:
27
28
29   1. An implementation of the Palacios host device interface that will
30      accept any URL from Palacios.  Currently, the only URL type it will
31      handle is user:<name>, but it should be clear how to extend with
32      other types.
33
34      Palacios opens a host device by issuing something like this:
35
36          palacios_host_dev_open( impl="user:foo" busclass=pci, opaque )
37
38      This will attempt to rendezvous with the user space device The
39      rendevzous retry and timeout periods can be set below.
40
41   2. An implementation of user: urls - the host interface is mapped
42      into an RPC-like interface to/from user space via a file
43      interface.   
44
45      The user space gets a file descriptor like this:
46
47      int vmfd = open("/dev/v3-vmX",...);
48
49      int devfd = ioctl(vmfd,V3_HOST_DEV_CONNECT,"user:foo"); 
50
51      This will attempt to rendezvous with the host side.
52
53      If it returns successfully, you can now issue synchronous,
54      blocking RPCs to the guest to read/write its memory and inject
55      irqs.  This means that a user->host request is handled
56      immediately, and independently of any host->user request. 
57
58      struct palacios_host_dev_user_op op;
59
60      // fill out op
61      op.type = PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST; 
62      ...
63
64      ioctl(devfd, V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL, &op);
65
66      // return value is # bytes read or written; or 0 if irq injected
67      // negative value is error
68
69      The interface from the host to the user side is asynchronous
70      blocking RPC.  Any host device will have at most one outstanding
71      request from palacios.  The implementation here stores the
72      request until the user side is ready to accept it.  The user side
73      can check if there is a request via a poll/select or an ioctl.
74      The ioctl also returns the needed size for the request structure.
75      After the user side has a request, it is expected to process it,
76      perhaps making user->host requests as described above, and then
77      return a response.  Only one host->user request should be in
78      progress at any time in the user space.
79
80      What this looks like is:
81      
82      poll(...devfd for read...) or select(...devfd for read...)
83
84      if (devfd is marked readable) { 
85          uint64_t size;
86
87          ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL,&size);
88          // returns 1 if there is a request, 0 if not, negative on err
89
90          struct palacios_host_dev_host_request_response *req;
91
92          req = allocate req to be at least size bytes long
93
94          ioctl(devfd,V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL,req)
95          // returns 1 if there is a request, 0 if not, negative on err
96          
97          // process request, perhaps using above user->host request
98          // build response structure
99          // resp.data_len == size of structure including relevant data at end
100
101          ioctl(devfd,V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL,resp);
102          // returns 0 if there is no outstanding request (user error)
103          // 1 on success, negative on error
104      }
105     
106
107 */
108
109
110 #define MAX_URL 256
111
112 #define RENDEZVOUS_WAIT_SECS  60
113 #define RENDEZVOUS_RETRY_SECS 1
114
115
116 struct palacios_host_device_user {
117     spinlock_t lock;
118     int      connected;    // is the user space connected to this?
119     int      waiting;      // am I waiting for a user-space response?
120
121     int      fd;           // what is the user space fd?
122
123     char     url[MAX_URL]; // what is the url describing the device
124
125     v3_guest_dev_t guestdev; // what is the palacios-side device
126
127     wait_queue_head_t  user_wait_queue; // user space processes waiting on us (should be only one)
128     wait_queue_head_t  host_wait_queue; // host threads (should only be one) waiting on user space
129
130     struct v3_guest                                *guest; // my guest
131     struct palacios_host_dev_host_request_response *req;   // curent request
132     struct palacios_host_dev_host_request_response *resp;  // curent response
133
134     struct list_head  node;   // for adding me to the list of hostdevs this VM has
135 };
136
137
138 /**************************************************************************************
139   Utility functions
140 *************************************************************************************/
141
142 static void palacios_host_dev_user_free(struct palacios_host_device_user *dev)
143 {
144     if (dev->req) {
145         kfree(dev->req);
146         dev->req=0;
147     } 
148     if (dev->resp) { 
149         kfree(dev->resp);
150         dev->resp=0;
151     }
152     kfree(dev);
153 }
154
155 static int palacios_resize_reqresp(struct palacios_host_dev_host_request_response **r, uint64_t data_size, int copy)
156 {
157     if (!*r) { 
158         // allocate it
159         *r = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL);
160         if (!*r) { 
161             return -1;
162         } else {
163             (*r)->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
164             return 0;
165         }
166     } else {
167         //let it go if it's big enough
168         uint64_t cur_len = (*r)->len-sizeof(struct palacios_host_dev_host_request_response);
169
170         if (data_size<=cur_len) { 
171             // do nothing
172             return 0;
173         } else {
174             struct palacios_host_dev_host_request_response *new;
175
176             if (!copy) { 
177                 kfree(*r);
178                 *r=0;
179             }
180             new = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL);
181             if (!new) { 
182                 return -1;
183             } else {
184                 new->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
185                 if (copy) { 
186                     memcpy(new->data,(*r)->data,(*r)->data_len-sizeof(struct palacios_host_dev_host_request_response));
187                     new->data_len=(*r)->data_len;
188                     kfree(*r);
189                 }
190                 *r=new;
191                 return 0;
192             }
193         }
194     }
195 }
196
197 static void cycle_request_response(struct palacios_host_device_user *dev)
198 {
199     // wake up user side so that polls fall through
200     wake_up_interruptible(&(dev->user_wait_queue));
201     // put us to sleep until the user side wakes us up
202     wait_event_interruptible((dev->host_wait_queue), (dev->waiting==0));
203 }
204
205 static void cycle_response_request(struct palacios_host_device_user *dev)
206 {
207     // wake up host side
208     wake_up_interruptible(&(dev->host_wait_queue));
209 }
210
211     
212 /*********************************************************************************************
213
214     Interface to user space
215
216  *********************************************************************************************/ 
217
218
219
220 static unsigned int host_dev_poll(struct file * filp, 
221                                   struct poll_table_struct * poll_tb) 
222 {
223
224     struct palacios_host_device_user * dev = filp->private_data;
225     unsigned long f;
226
227     if (!dev->connected) { 
228         return -EFAULT;
229     }
230
231     spin_lock_irqsave(&(dev->lock),f);
232
233     if (dev->waiting) { 
234         // Yes, we have a request if you want it!
235         spin_unlock_irqrestore(&(dev->lock),f);
236         return  POLLIN | POLLRDNORM;
237     } 
238
239     // No request yet, so we need to wait for one to show up.
240
241     // register ourselves on the user wait queue
242     poll_wait(filp, &(dev->user_wait_queue), poll_tb);
243
244     spin_unlock_irqrestore(&(dev->lock),f);
245
246     // We will get called again when that queue is woken up
247
248     return 0;
249 }
250
251
252 static int host_dev_release(struct inode * i, struct file * filp) 
253 {
254     struct palacios_host_device_user *dev = filp->private_data;
255     unsigned long f;
256
257     printk("palacios: user side is closing host device \"%s\"\n",dev->url);
258     
259     spin_lock_irqsave(&(dev->lock), f);
260     dev->connected = 0;
261     spin_unlock_irqrestore(&(dev->lock), f);
262
263     // it is the palacios->host interface's responsibility to ignore
264     // reads/writes until connected is true
265
266     return 0;
267 }
268
269
270 static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, unsigned long arg)
271 {
272     void __user *argp = (void __user *)arg;
273
274     struct palacios_host_device_user *dev = fp->private_data;
275
276
277     if (!dev->connected) { 
278         return -EFAULT;
279     }
280     
281     switch (val) { 
282         case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
283             
284             struct palacios_host_dev_user_op op;
285             
286             if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) { 
287                 printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
288                 return -EFAULT;
289             }
290             
291             switch (op.type) { 
292                 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
293                     void *temp = kmalloc(op.len,GFP_KERNEL);
294
295                     if (!temp) { 
296                         printk("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
297                         return -EFAULT;
298                     }
299                     
300                     if (v3_host_dev_read_guest_mem(dev->guestdev,
301                                                    dev,
302                                                    op.gpa,
303                                                    temp,
304                                                    op.len) != op.len) {
305                         printk("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
306                         kfree(temp);
307                         return -EFAULT;
308                     }
309                     
310                     if (copy_to_user(op.data,temp,op.len)) { 
311                         printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
312                         kfree(temp);
313                         return -EFAULT;
314                     }
315
316                     kfree(temp);
317
318                     return op.len;
319                 }
320                     break;
321                     
322
323                 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
324
325                     void *temp = kmalloc(op.len,GFP_KERNEL);
326
327                     if (!temp) { 
328                         printk("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
329                         return -EFAULT;
330                     }
331                     
332                     if (copy_from_user(temp,op.data,op.len)) { 
333                         printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
334                         kfree(temp);
335                         return -EFAULT;
336                     }
337                     
338                     if (v3_host_dev_write_guest_mem(dev->guestdev,
339                                                     dev,
340                                                     op.gpa,
341                                                     temp,
342                                                     op.len) != op.len) {
343                         printk("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
344                         kfree(temp);
345                         return -EFAULT;
346                     }
347
348                     kfree(temp);
349                     
350                     return op.len;
351                 }
352                     break;
353
354                 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
355
356                     return  v3_host_dev_raise_irq(dev->guestdev, dev, op.irq);
357                 }
358                     break;
359
360                 default:
361                     printk("palacios: unknown user request to host device \"%s\"\n",dev->url);
362                     return -EFAULT;
363                     break;
364             }
365         }
366             break;
367
368         case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
369             
370             unsigned long f;
371             
372             spin_lock_irqsave(&(dev->lock),f);
373             
374             if (!(dev->waiting)) { 
375                 spin_unlock_irqrestore(&(dev->lock),f);
376                 return 0; // no request available now
377             } 
378             
379             if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { 
380                 printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
381                 spin_unlock_irqrestore(&(dev->lock),f);
382                 return -EFAULT; // failed to copy!
383             }
384             
385             spin_unlock_irqrestore(&(dev->lock),f);
386
387             return 1; // have request for you
388             
389         }
390             
391             break;
392             
393         case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
394             
395             unsigned long f;
396             
397             spin_lock_irqsave(&(dev->lock),f);
398             
399             if (!(dev->waiting)) { 
400                 spin_unlock_irqrestore(&(dev->lock),f);
401                 return 0; // no request available now
402             } 
403             
404             if (copy_to_user(argp,dev->req,dev->req->data_len)) { 
405                 printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
406                 spin_unlock_irqrestore(&(dev->lock),f);
407                 return -EFAULT; // failed to copy!
408             }
409             
410             spin_unlock_irqrestore(&(dev->lock),f);
411             
412             return 1; // copied request for you
413         }
414             break;
415             
416         case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
417
418             unsigned long f;
419             uint64_t user_datalen;
420             
421             spin_lock_irqsave(&(dev->lock),f);
422             
423             if (!(dev->waiting)) { 
424                 spin_unlock_irqrestore(&(dev->lock),f);
425                 return 0; // no request outstanding, so we do not need a response!
426             }
427             
428             if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { 
429                 printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
430                 spin_unlock_irqrestore(&(dev->lock),f);
431                 return -EFAULT; // failed to copy!
432             } 
433             
434             if (palacios_resize_reqresp(&(dev->resp),user_datalen,0)) {
435                 printk("palacios: unable to resize to accept request of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
436                 spin_unlock_irqrestore(&(dev->lock),f);
437                 return -EFAULT;
438             } 
439             
440             if (copy_from_user(dev->resp, argp, user_datalen)) { 
441                 printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
442                 spin_unlock_irqrestore(&(dev->lock),f);
443                 return -EFAULT; // failed to copy!
444             } 
445             
446             // now have valid response!
447             dev->waiting=0;
448
449             // wake the palacios side up so that it sees it
450             cycle_response_request(dev);
451
452             spin_unlock_irqrestore(&(dev->lock),f);
453
454             return 1; // done
455         }
456             break;
457             
458         default:
459             printk("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
460             return -EFAULT;
461             break;
462     }
463     
464 }
465
466
467
468
469 static struct file_operations host_dev_fops = {
470     .poll     = host_dev_poll,
471     .release  = host_dev_release,
472     .ioctl    = host_dev_ioctl,
473 };
474
475
476
477     
478 int connect_host_dev(struct v3_guest * guest, char *url) 
479 {
480     struct palacios_host_device_user *dev;
481     unsigned long f1, f2;
482     int i;
483
484     // currently only support user: types:
485     if (strncasecmp(url,"user:",5)) { 
486         printk("palacios: do not currently support host devices of type in \"%s\"\n",url);
487         return -1;
488     }
489     
490     printk("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
491     
492     // We will scan the list looking for the relevant
493     // URL.  If we don't find it after a while, we give up
494     
495     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
496         spin_lock_irqsave(&(guest->hostdev.lock),f1);
497         list_for_each_entry(dev,&(guest->hostdev.devs), node) {
498             if (!strncasecmp(url,dev->url,MAX_URL)) { 
499                 // found it
500                 spin_lock_irqsave(&(dev->lock),f2);
501                 if (dev->connected) { 
502                     printk("palacios: device for \"%s\" is already connected!\n",url);
503                     spin_unlock_irqrestore(&(dev->lock),f2);
504                     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
505                     return -1;
506                 } else {
507                     dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
508                     if (dev->fd<0) { 
509                         printk("palacios: cannot create fd for device \"%s\"\n",url);
510                         spin_unlock_irqrestore(&(dev->lock),f2);
511                         spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
512                         return -1;
513                     }
514                     dev->connected=1;
515                     dev->waiting=0;
516                     if (dev->req) { 
517                         kfree(dev->req);
518                         dev->req=0;
519                     } 
520                     if (dev->resp) { 
521                         kfree(dev->resp);
522                         dev->resp=0;
523                     }
524                     printk("palacios: connected fd for device \"%s\"\n",url);
525                     spin_unlock_irqrestore(&(dev->lock),f2);
526                     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
527                     return dev->fd;
528                 }
529                 spin_unlock_irqrestore(&(dev->lock),f2);
530             }
531         }
532         spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
533         
534         ssleep(RENDEZVOUS_RETRY_SECS);
535     }
536     
537     printk("palacios: timeout waiting for connection for device \"%s\"",url);
538     
539     return -1;
540     
541 }
542
543
544
545
546
547
548
549
550 /***************************************************************************************
551
552    Following this is the implementation of the palacios->host interface
553
554 **************************************************************************************/
555
556 static v3_host_dev_t palacios_host_dev_open(char *url,
557                                             v3_bus_class_t bus,
558                                             v3_guest_dev_t gdev,
559                                             void *host_priv_data)
560 {
561     struct v3_guest *guest= (struct v3_guest*)host_priv_data;
562     struct palacios_host_device_user *dev;
563     unsigned long f1,f2;
564     int i;
565
566     /*
567       I will create the device in the list and then wait
568       for the user side to attach
569     */
570
571
572     if (strncasecmp(url,"user:",5)) { 
573         printk("palacios: do not currently support devices of type in \"%s\"\n",url);
574         return NULL;
575     }
576
577     // Check to see if a device of this url already exists, which would be ugly
578     spin_lock_irqsave(&(guest->hostdev.lock),f1);
579     list_for_each_entry(dev,&(guest->hostdev.devs), node) {
580         if (!strncasecmp(url,dev->url,MAX_URL)) { 
581             // found it
582             spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
583             printk("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
584             return NULL;
585         }
586     }
587     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
588
589
590     printk("palacios: creating host device \"%s\"\n",url);
591
592     dev = kmalloc(sizeof(struct palacios_host_device_user),GFP_KERNEL);
593     
594     if (!dev) { 
595         printk("palacios: cannot allocate for host device \"%s\"\n",url);
596         return NULL;
597     }
598
599     memset(dev,0,sizeof(struct palacios_host_device_user));
600     
601     strncpy(dev->url,url,MAX_URL);
602     
603     dev->guestdev=gdev;
604     
605     dev->guest=guest;
606
607     spin_lock_init(&(dev->lock));
608
609     init_waitqueue_head(&(dev->user_wait_queue));
610     init_waitqueue_head(&(dev->host_wait_queue));
611
612     printk("palacios: attempting to rendezvous with user side of host device \"%s\"\n",url);
613     
614     // Insert ourselves into the list
615     spin_lock_irqsave(&(guest->hostdev.lock),f1);
616     list_add(&(dev->node),&(guest->hostdev.devs));
617     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
618
619     
620     // Now wait until we are noticed!
621     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
622         spin_lock_irqsave(&(dev->lock),f2);
623         if (dev->connected){ 
624             printk("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
625             spin_unlock_irqrestore(&(dev->lock),f2);
626             return dev;
627         }
628         spin_unlock_irqrestore(&(dev->lock),f2);
629         ssleep(RENDEZVOUS_RETRY_SECS);
630     }
631     
632     printk("palacios: timeout waiting for user side to connect to host device \"%s\"",url);
633     
634     // get us out of the list
635     spin_lock_irqsave(&(guest->hostdev.lock),f1);
636     list_del(&(dev->node));
637     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
638     
639     palacios_host_dev_user_free(dev);
640     
641     return NULL;
642 }
643
644 static int palacios_host_dev_close(v3_host_dev_t hostdev)
645 {
646     unsigned long f1, f2;
647
648     struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
649     
650     printk("palacios: closing host device \"%s\"\n",dev->url);
651
652     spin_lock_irqsave(&(dev->guest->hostdev.lock),f1);
653
654     spin_lock_irqsave(&(dev->lock),f2);
655
656     if (dev->connected) { 
657         dev->connected=0;
658         // After this, any user side request will return -EFAULT
659     }
660
661     list_del(&(dev->node));
662     
663     spin_unlock_irqrestore(&(dev->lock),f2);
664     spin_unlock_irqrestore(&(dev->guest->hostdev.lock),f1);
665     
666     palacios_host_dev_user_free(dev);
667
668     return 0;
669 }
670
671
672
673         
674 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
675                                           uint16_t      port,
676                                           void          *dest,
677                                           uint64_t      len)
678 {
679     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
680     unsigned long f;
681     uint64_t op_len;
682
683     spin_lock_irqsave(&(dev->lock),f);
684     
685     if (dev->waiting) { 
686         printk("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);
687         spin_unlock_irqrestore(&(dev->lock),f);
688         return 0;
689     }
690
691     if (!dev->connected) {
692         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
693         spin_unlock_irqrestore(&(dev->lock),f);
694         return 0;
695     }
696     
697     // resize request and response in case they will need it
698     palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
699
700     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
701     dev->req->port=port;
702     dev->req->op_len=len;
703     dev->req->gpa=0;
704     dev->req->conf_addr=0;
705     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
706
707     dev->waiting=1;
708     
709     spin_unlock_irqrestore(&(dev->lock),f);
710
711     // hand over to the user space and wait for it to respond
712     cycle_request_response(dev);
713
714     // We're back!   So now we'll hand the response back to Palacios
715
716     spin_lock_irqsave(&(dev->lock),f);
717
718     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
719
720     memcpy(dest,dev->resp->data, op_len);
721     
722     spin_unlock_irqrestore(&(dev->lock),f);
723
724     return op_len;
725 }
726
727 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
728                                            void *        gpa,
729                                            void          *dest,
730                                            uint64_t      len)
731 {
732     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
733     unsigned long f;
734     uint64_t op_len;
735
736     spin_lock_irqsave(&(dev->lock),f);
737     
738     if (dev->waiting) { 
739         printk("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
740         spin_unlock_irqrestore(&(dev->lock),f);
741         return 0;
742     }
743     if (!dev->connected) {
744         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
745         spin_unlock_irqrestore(&(dev->lock),f);
746         return 0;
747     }
748     
749     // resize request and response in case they will need it
750     palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
751
752     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
753     dev->req->port=0;
754     dev->req->op_len=len;
755     dev->req->gpa=gpa;
756     dev->req->conf_addr=0;
757     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
758
759     dev->waiting=1;
760     
761     spin_unlock_irqrestore(&(dev->lock),f);
762
763     // hand over to the user space and wait for it to respond
764     cycle_request_response(dev);
765
766     // We're back!   So now we'll hand the response back to Palacios
767
768     spin_lock_irqsave(&(dev->lock),f);
769
770     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
771
772     memcpy(dest,dev->resp->data, op_len);
773     
774     spin_unlock_irqrestore(&(dev->lock),f);
775
776     return op_len;
777 }
778
779 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
780                                             uint64_t      offset,
781                                             void          *dest,
782                                             uint64_t      len)
783 {
784     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
785     unsigned long f;
786     uint64_t op_len;
787
788     spin_lock_irqsave(&(dev->lock),f);
789     
790     if (dev->waiting) { 
791         printk("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
792         spin_unlock_irqrestore(&(dev->lock),f);
793         return 0;
794     }
795     if (!dev->connected) {
796         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
797         spin_unlock_irqrestore(&(dev->lock),f);
798         return 0;
799     }
800     
801     // resize request and response in case they will need it
802     palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
803
804     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
805     dev->req->port=0;
806     dev->req->op_len=len;
807     dev->req->gpa=0;
808     dev->req->conf_addr=offset;
809     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
810
811     dev->waiting=1;
812     
813     spin_unlock_irqrestore(&(dev->lock),f);
814
815     // hand over to the user space and wait for it to respond
816     cycle_request_response(dev);
817
818     // We're back!   So now we'll hand the response back to Palacios
819
820     spin_lock_irqsave(&(dev->lock),f);
821
822     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
823
824     memcpy(dest,dev->resp->data, op_len);
825     
826     spin_unlock_irqrestore(&(dev->lock),f);
827
828     return op_len;
829 }
830
831
832 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
833                                            uint16_t      port,
834                                            void          *src,
835                                            uint64_t      len)
836 {
837     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
838     unsigned long f;
839     uint64_t op_len;
840
841     spin_lock_irqsave(&(dev->lock),f);
842     
843     if (dev->waiting) { 
844         printk("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);
845         spin_unlock_irqrestore(&(dev->lock),f);
846         return 0;
847     }
848     if (!dev->connected) {
849         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
850         spin_unlock_irqrestore(&(dev->lock),f);
851         return 0;
852     }
853
854     // resize request and response in case they will need it
855     palacios_resize_reqresp(&(dev->req),len,0); // make room for data
856
857     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
858     dev->req->port=port;
859     dev->req->op_len=len;
860     dev->req->gpa=0;
861     dev->req->conf_addr=0;
862     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
863
864     memcpy(dev->req->data,src,len);
865
866     dev->waiting=1;
867     
868     spin_unlock_irqrestore(&(dev->lock),f);
869
870     // hand over to the user space and wait for it to respond
871     cycle_request_response(dev);
872
873     // We're back!   So now we'll hand the response back to Palacios
874
875     spin_lock_irqsave(&(dev->lock),f);
876
877     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
878
879     spin_unlock_irqrestore(&(dev->lock),f);
880
881     return op_len;
882 }
883
884
885 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
886                                             void *        gpa,
887                                             void          *src,
888                                             uint64_t      len)
889 {
890     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
891     unsigned long f;
892     uint64_t op_len;
893
894     spin_lock_irqsave(&(dev->lock),f);
895     
896     if (dev->waiting) { 
897         printk("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
898         spin_unlock_irqrestore(&(dev->lock),f);
899         return 0;
900     }
901     if (!dev->connected) {
902         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
903         spin_unlock_irqrestore(&(dev->lock),f);
904         return 0;
905     }
906     
907     // resize request and response in case they will need it
908     palacios_resize_reqresp(&(dev->req),len,0); // make room for data
909
910     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
911     dev->req->port=0;
912     dev->req->op_len=len;
913     dev->req->gpa=gpa;
914     dev->req->conf_addr=0;
915     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
916
917     memcpy(dev->req->data,src,len);
918
919     dev->waiting=1;
920     
921     spin_unlock_irqrestore(&(dev->lock),f);
922
923     // hand over to the user space and wait for it to respond
924     cycle_request_response(dev);
925
926     // We're back!   So now we'll hand the response back to Palacios
927
928     spin_lock_irqsave(&(dev->lock),f);
929
930     op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
931
932     spin_unlock_irqrestore(&(dev->lock),f);
933
934     return op_len;
935 }
936
937
938 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
939 {
940     // we don't care
941     return 0;
942 }
943  
944
945
946 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
947                                              uint64_t      offset,
948                                              void          *src,
949                                              uint64_t      len)
950 {
951     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
952     unsigned long f;
953     uint64_t op_len;
954
955     spin_lock_irqsave(&(dev->lock),f);
956     
957     if (dev->waiting) { 
958         printk("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
959         spin_unlock_irqrestore(&(dev->lock),f);
960         return 0;
961     }
962     if (!dev->connected) {
963         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
964         spin_unlock_irqrestore(&(dev->lock),f);
965         return 0;
966     }
967     
968     // resize request and response in case they will need it
969     palacios_resize_reqresp(&(dev->req),len,0); // make room for data
970
971     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
972     dev->req->port=0;
973     dev->req->op_len=len;
974     dev->req->gpa=0;
975     dev->req->conf_addr=offset;
976     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
977
978     memcpy(dev->req->data,src,len);
979
980     dev->waiting=1;
981     
982     spin_unlock_irqrestore(&(dev->lock),f);
983
984     // hand over to the user space and wait for it to respond
985     cycle_request_response(dev);
986
987     // We're back!   So now we'll hand the response back to Palacios
988
989     spin_lock_irqsave(&(dev->lock),f);
990
991     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
992
993     spin_unlock_irqrestore(&(dev->lock),f);
994
995     return op_len;
996  }
997  
998  
999
1000
1001
1002
1003 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1004     .open                       = palacios_host_dev_open,
1005     .close                      = palacios_host_dev_close,
1006     .read_io                    = palacios_host_dev_read_io,
1007     .write_io                   = palacios_host_dev_write_io,
1008     .read_mem                   = palacios_host_dev_read_mem,
1009     .write_mem                  = palacios_host_dev_write_mem,
1010     .read_config                = palacios_host_dev_read_conf,
1011     .write_config               = palacios_host_dev_write_conf,
1012     .ack_irq                    = palacios_host_dev_ack_irq,
1013 };
1014
1015
1016
1017 int palacios_init_host_dev( void ) {
1018     V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1019     
1020     return 0;
1021 }