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.


Ported keyed stream support from monolithic embedding
[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 static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, unsigned long arg)
270 {
271     void __user *argp = (void __user *)arg;
272
273     struct palacios_host_device_user *dev = fp->private_data;
274
275     if (!dev->connected) { 
276         return -EFAULT;
277     }
278     
279     switch (val) { 
280         case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
281             
282             struct palacios_host_dev_user_op op;
283             
284             if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) { 
285                 printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
286                 return -EFAULT;
287             }
288             
289             switch (op.type) { 
290                 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
291                     void *temp = kmalloc(op.len,GFP_KERNEL);
292
293                     if (!temp) { 
294                         printk("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
295                         return -EFAULT;
296                     }
297                     
298                     if (v3_host_dev_read_guest_mem(dev->guestdev,
299                                                    dev,
300                                                    op.gpa,
301                                                    temp,
302                                                    op.len) != op.len) {
303                         printk("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
304                         kfree(temp);
305                         return -EFAULT;
306                     }
307                     
308                     if (copy_to_user(op.data,temp,op.len)) { 
309                         printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
310                         kfree(temp);
311                         return -EFAULT;
312                     }
313
314                     kfree(temp);
315
316                     return op.len;
317                 }
318                     break;
319                     
320
321                 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
322
323                     void *temp = kmalloc(op.len,GFP_KERNEL);
324
325                     if (!temp) { 
326                         printk("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
327                         return -EFAULT;
328                     }
329                     
330                     if (copy_from_user(temp,op.data,op.len)) { 
331                         printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
332                         kfree(temp);
333                         return -EFAULT;
334                     }
335                     
336                     if (v3_host_dev_write_guest_mem(dev->guestdev,
337                                                     dev,
338                                                     op.gpa,
339                                                     temp,
340                                                     op.len) != op.len) {
341                         printk("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
342                         kfree(temp);
343                         return -EFAULT;
344                     }
345
346                     kfree(temp);
347                     
348                     return op.len;
349                 }
350                     break;
351
352                 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
353
354                     return  v3_host_dev_raise_irq(dev->guestdev, dev, op.irq);
355                 }
356                     break;
357
358                 default:
359                     printk("palacios: unknown user request to host device \"%s\"\n",dev->url);
360                     return -EFAULT;
361                     break;
362             }
363         }
364             break;
365
366         case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
367             
368             unsigned long f;
369             
370             spin_lock_irqsave(&(dev->lock),f);
371             
372             if (!(dev->waiting)) { 
373                 spin_unlock_irqrestore(&(dev->lock),f);
374                 return 0; // no request available now
375             } 
376             
377             if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { 
378                 printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
379                 spin_unlock_irqrestore(&(dev->lock),f);
380                 return -EFAULT; // failed to copy!
381             }
382             
383             spin_unlock_irqrestore(&(dev->lock),f);
384             
385             return 1; // have request for you
386             
387         }
388             
389             break;
390             
391         case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
392             
393             unsigned long f;
394             
395             spin_lock_irqsave(&(dev->lock),f);
396             
397             if (!(dev->waiting)) { 
398                 spin_unlock_irqrestore(&(dev->lock),f);
399                 return 0; // no request available now
400             } 
401             
402             if (copy_to_user(argp,dev->req,dev->req->data_len)) { 
403                 printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
404                 spin_unlock_irqrestore(&(dev->lock),f);
405                 return -EFAULT; // failed to copy!
406             }
407             
408             spin_unlock_irqrestore(&(dev->lock),f);
409             
410             return 1; // copied request for you
411         }
412             break;
413             
414         case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
415
416             unsigned long f;
417             uint64_t user_datalen;
418             
419             spin_lock_irqsave(&(dev->lock),f);
420             
421             if (!(dev->waiting)) { 
422                 spin_unlock_irqrestore(&(dev->lock),f);
423                 return 0; // no request outstanding, so we do not need a response!
424             }
425             
426             if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { 
427                 printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
428                 spin_unlock_irqrestore(&(dev->lock),f);
429                 return -EFAULT; // failed to copy!
430             } 
431             
432             if (palacios_resize_reqresp(&(dev->resp),user_datalen,0)) {
433                 printk("palacios: unable to resize to accept request of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
434                 spin_unlock_irqrestore(&(dev->lock),f);
435                 return -EFAULT;
436             } 
437             
438             if (copy_from_user(dev->resp, argp, user_datalen)) { 
439                 printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
440                 spin_unlock_irqrestore(&(dev->lock),f);
441                 return -EFAULT; // failed to copy!
442             } 
443             
444             // now have valid response!
445             dev->waiting=0;
446
447             // wake the palacios side up so that it sees it
448             cycle_response_request(dev);
449
450             spin_unlock_irqrestore(&(dev->lock),f);
451
452             return 1; // done
453         }
454             break;
455             
456         default:
457             printk("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
458             return -EFAULT;
459             break;
460     }
461     
462 }
463
464
465 static struct file_operations host_dev_fops = {
466     .poll     = host_dev_poll,
467     .release  = host_dev_release,
468     .ioctl    = host_dev_ioctl,
469 };
470
471
472
473     
474 int connect_host_dev(struct v3_guest * guest, char *url) 
475 {
476     struct palacios_host_device_user *dev;
477     unsigned long f1, f2;
478     int i;
479
480     // currently only support user: types:
481     if (strncasecmp(url,"user:",5)) { 
482         printk("palacios: do not currently support host devices of type in \"%s\"\n",url);
483         return -1;
484     }
485     
486     printk("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
487     
488     // We will scan the list looking for the relevant
489     // URL.  If we don't find it after a while, we give up
490     
491     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
492         spin_lock_irqsave(&(guest->hostdev.lock),f1);
493         list_for_each_entry(dev,&(guest->hostdev.devs), node) {
494             if (!strncasecmp(url,dev->url,MAX_URL)) { 
495                 // found it
496                 spin_lock_irqsave(&(dev->lock),f2);
497                 if (dev->connected) { 
498                     printk("palacios: device for \"%s\" is already connected!\n",url);
499                     spin_unlock_irqrestore(&(dev->lock),f2);
500                     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
501                     return -1;
502                 } else {
503                     dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
504                     if (dev->fd<0) { 
505                         printk("palacios: cannot create fd for device \"%s\"\n",url);
506                         spin_unlock_irqrestore(&(dev->lock),f2);
507                         spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
508                         return -1;
509                     }
510                     dev->connected=1;
511                     dev->waiting=0;
512                     if (dev->req) { 
513                         kfree(dev->req);
514                         dev->req=0;
515                     } 
516                     if (dev->resp) { 
517                         kfree(dev->resp);
518                         dev->resp=0;
519                     }
520                     printk("palacios: connected fd for device \"%s\"\n",url);
521                     spin_unlock_irqrestore(&(dev->lock),f2);
522                     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
523                     return dev->fd;
524                 }
525                 spin_unlock_irqrestore(&(dev->lock),f2);
526             }
527         }
528         spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
529         
530         ssleep(RENDEZVOUS_RETRY_SECS);
531     }
532     
533     printk("palacios: timeout waiting for connection for device \"%s\"",url);
534     
535     return -1;
536     
537 }
538
539
540
541
542
543
544
545
546 /***************************************************************************************
547
548    Following this is the implementation of the palacios->host interface
549
550 **************************************************************************************/
551
552 static v3_host_dev_t palacios_host_dev_open(char *url,
553                                             v3_bus_class_t bus,
554                                             v3_guest_dev_t gdev,
555                                             void *host_priv_data)
556 {
557     struct v3_guest *guest= (struct v3_guest*)host_priv_data;
558     struct palacios_host_device_user *dev;
559     unsigned long f1,f2;
560     int i;
561
562     /*
563       I will create the device in the list and then wait
564       for the user side to attach
565     */
566
567
568     if (strncasecmp(url,"user:",5)) { 
569         printk("palacios: do not currently support devices of type in \"%s\"\n",url);
570         return NULL;
571     }
572
573     // Check to see if a device of this url already exists, which would be ugly
574     spin_lock_irqsave(&(guest->hostdev.lock),f1);
575     list_for_each_entry(dev,&(guest->hostdev.devs), node) {
576         if (!strncasecmp(url,dev->url,MAX_URL)) { 
577             // found it
578             spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
579             printk("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
580             return NULL;
581         }
582     }
583     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
584
585
586     printk("palacios: creating host device \"%s\"\n",url);
587
588     dev = kmalloc(sizeof(struct palacios_host_device_user),GFP_KERNEL);
589     
590     if (!dev) { 
591         printk("palacios: cannot allocate for host device \"%s\"\n",url);
592         return NULL;
593     }
594
595     memset(dev,0,sizeof(struct palacios_host_device_user));
596     
597     strncpy(dev->url,url,MAX_URL);
598     
599     dev->guestdev=gdev;
600     
601     dev->guest=guest;
602
603     spin_lock_init(&(dev->lock));
604
605     init_waitqueue_head(&(dev->user_wait_queue));
606     init_waitqueue_head(&(dev->host_wait_queue));
607
608     printk("palacios: attempting to rendezvous with user side of host device \"%s\"\n",url);
609     
610     // Insert ourselves into the list
611     spin_lock_irqsave(&(guest->hostdev.lock),f1);
612     list_add(&(dev->node),&(guest->hostdev.devs));
613     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
614
615     
616     // Now wait until we are noticed!
617     for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
618         spin_lock_irqsave(&(dev->lock),f2);
619         if (dev->connected){ 
620             printk("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
621             spin_unlock_irqrestore(&(dev->lock),f2);
622             return dev;
623         }
624         spin_unlock_irqrestore(&(dev->lock),f2);
625         ssleep(RENDEZVOUS_RETRY_SECS);
626     }
627     
628     printk("palacios: timeout waiting for user side to connect to host device \"%s\"",url);
629     
630     // get us out of the list
631     spin_lock_irqsave(&(guest->hostdev.lock),f1);
632     list_del(&(dev->node));
633     spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
634     
635     palacios_host_dev_user_free(dev);
636     
637     return NULL;
638 }
639
640 static int palacios_host_dev_close(v3_host_dev_t hostdev)
641 {
642     unsigned long f1, f2;
643
644     struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
645     
646     printk("palacios: closing host device \"%s\"\n",dev->url);
647
648     spin_lock_irqsave(&(dev->guest->hostdev.lock),f1);
649
650     spin_lock_irqsave(&(dev->lock),f2);
651
652     if (dev->connected) { 
653         dev->connected=0;
654         // After this, any user side request will return -EFAULT
655     }
656
657     list_del(&(dev->node));
658     
659     spin_unlock_irqrestore(&(dev->lock),f2);
660     spin_unlock_irqrestore(&(dev->guest->hostdev.lock),f1);
661     
662     palacios_host_dev_user_free(dev);
663
664     return 0;
665 }
666
667
668
669         
670 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
671                                           uint16_t      port,
672                                           void          *dest,
673                                           uint64_t      len)
674 {
675     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
676     unsigned long f;
677     uint64_t op_len;
678
679     spin_lock_irqsave(&(dev->lock),f);
680     
681     if (dev->waiting) { 
682         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);
683         spin_unlock_irqrestore(&(dev->lock),f);
684         return 0;
685     }
686
687     if (!dev->connected) {
688         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
689         spin_unlock_irqrestore(&(dev->lock),f);
690         return 0;
691     }
692     
693     // resize request and response in case they will need it
694     palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
695
696     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
697     dev->req->port=port;
698     dev->req->op_len=len;
699     dev->req->gpa=0;
700     dev->req->conf_addr=0;
701     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
702
703     dev->waiting=1;
704     
705     spin_unlock_irqrestore(&(dev->lock),f);
706
707     // hand over to the user space and wait for it to respond
708     cycle_request_response(dev);
709
710     // We're back!   So now we'll hand the response back to Palacios
711
712     spin_lock_irqsave(&(dev->lock),f);
713
714     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
715
716     memcpy(dest,dev->resp->data, op_len);
717     
718     spin_unlock_irqrestore(&(dev->lock),f);
719
720     return op_len;
721 }
722
723 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
724                                            void *        gpa,
725                                            void          *dest,
726                                            uint64_t      len)
727 {
728     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
729     unsigned long f;
730     uint64_t op_len;
731
732     spin_lock_irqsave(&(dev->lock),f);
733     
734     if (dev->waiting) { 
735         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);
736         spin_unlock_irqrestore(&(dev->lock),f);
737         return 0;
738     }
739     if (!dev->connected) {
740         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
741         spin_unlock_irqrestore(&(dev->lock),f);
742         return 0;
743     }
744     
745     // resize request and response in case they will need it
746     palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
747
748     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
749     dev->req->port=0;
750     dev->req->op_len=len;
751     dev->req->gpa=gpa;
752     dev->req->conf_addr=0;
753     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
754
755     dev->waiting=1;
756     
757     spin_unlock_irqrestore(&(dev->lock),f);
758
759     // hand over to the user space and wait for it to respond
760     cycle_request_response(dev);
761
762     // We're back!   So now we'll hand the response back to Palacios
763
764     spin_lock_irqsave(&(dev->lock),f);
765
766     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
767
768     memcpy(dest,dev->resp->data, op_len);
769     
770     spin_unlock_irqrestore(&(dev->lock),f);
771
772     return op_len;
773 }
774
775 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
776                                             uint64_t      offset,
777                                             void          *dest,
778                                             uint64_t      len)
779 {
780     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
781     unsigned long f;
782     uint64_t op_len;
783
784     spin_lock_irqsave(&(dev->lock),f);
785     
786     if (dev->waiting) { 
787         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);
788         spin_unlock_irqrestore(&(dev->lock),f);
789         return 0;
790     }
791     if (!dev->connected) {
792         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
793         spin_unlock_irqrestore(&(dev->lock),f);
794         return 0;
795     }
796     
797     // resize request and response in case they will need it
798     palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data
799
800     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
801     dev->req->port=0;
802     dev->req->op_len=len;
803     dev->req->gpa=0;
804     dev->req->conf_addr=offset;
805     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
806
807     dev->waiting=1;
808     
809     spin_unlock_irqrestore(&(dev->lock),f);
810
811     // hand over to the user space and wait for it to respond
812     cycle_request_response(dev);
813
814     // We're back!   So now we'll hand the response back to Palacios
815
816     spin_lock_irqsave(&(dev->lock),f);
817
818     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
819
820     memcpy(dest,dev->resp->data, op_len);
821     
822     spin_unlock_irqrestore(&(dev->lock),f);
823
824     return op_len;
825 }
826
827
828 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
829                                            uint16_t      port,
830                                            void          *src,
831                                            uint64_t      len)
832 {
833     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
834     unsigned long f;
835     uint64_t op_len;
836
837     spin_lock_irqsave(&(dev->lock),f);
838     
839     if (dev->waiting) { 
840         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);
841         spin_unlock_irqrestore(&(dev->lock),f);
842         return 0;
843     }
844     if (!dev->connected) {
845         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
846         spin_unlock_irqrestore(&(dev->lock),f);
847         return 0;
848     }
849     
850     // resize request and response in case they will need it
851     palacios_resize_reqresp(&(dev->req),len,0); // make room for data
852
853     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
854     dev->req->port=port;
855     dev->req->op_len=len;
856     dev->req->gpa=0;
857     dev->req->conf_addr=0;
858     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
859
860     memcpy(dev->req->data,src,len);
861
862     dev->waiting=1;
863     
864     spin_unlock_irqrestore(&(dev->lock),f);
865
866     // hand over to the user space and wait for it to respond
867     cycle_request_response(dev);
868
869     // We're back!   So now we'll hand the response back to Palacios
870
871     spin_lock_irqsave(&(dev->lock),f);
872
873     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
874
875     spin_unlock_irqrestore(&(dev->lock),f);
876
877     return op_len;
878 }
879
880
881 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
882                                             void *        gpa,
883                                             void          *src,
884                                             uint64_t      len)
885 {
886     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
887     unsigned long f;
888     uint64_t op_len;
889
890     spin_lock_irqsave(&(dev->lock),f);
891     
892     if (dev->waiting) { 
893         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);
894         spin_unlock_irqrestore(&(dev->lock),f);
895         return 0;
896     }
897     if (!dev->connected) {
898         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
899         spin_unlock_irqrestore(&(dev->lock),f);
900         return 0;
901     }
902     
903     // resize request and response in case they will need it
904     palacios_resize_reqresp(&(dev->req),len,0); // make room for data
905
906     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
907     dev->req->port=0;
908     dev->req->op_len=len;
909     dev->req->gpa=gpa;
910     dev->req->conf_addr=0;
911     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
912
913     memcpy(dev->req->data,src,len);
914
915     dev->waiting=1;
916     
917     spin_unlock_irqrestore(&(dev->lock),f);
918
919     // hand over to the user space and wait for it to respond
920     cycle_request_response(dev);
921
922     // We're back!   So now we'll hand the response back to Palacios
923
924     spin_lock_irqsave(&(dev->lock),f);
925
926     op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
927
928     spin_unlock_irqrestore(&(dev->lock),f);
929
930     return op_len;
931 }
932
933
934 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
935 {
936     // we don't care
937     return 0;
938 }
939  
940
941
942 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
943                                              uint64_t      offset,
944                                              void          *src,
945                                              uint64_t      len)
946 {
947     struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
948     unsigned long f;
949     uint64_t op_len;
950
951     spin_lock_irqsave(&(dev->lock),f);
952     
953     if (dev->waiting) { 
954         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);
955         spin_unlock_irqrestore(&(dev->lock),f);
956         return 0;
957     }
958     if (!dev->connected) {
959         printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
960         spin_unlock_irqrestore(&(dev->lock),f);
961         return 0;
962     }
963     
964     // resize request and response in case they will need it
965     palacios_resize_reqresp(&(dev->req),len,0); // make room for data
966
967     dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
968     dev->req->port=0;
969     dev->req->op_len=len;
970     dev->req->gpa=0;
971     dev->req->conf_addr=offset;
972     dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
973
974     memcpy(dev->req->data,src,len);
975
976     dev->waiting=1;
977     
978     spin_unlock_irqrestore(&(dev->lock),f);
979
980     // hand over to the user space and wait for it to respond
981     cycle_request_response(dev);
982
983     // We're back!   So now we'll hand the response back to Palacios
984
985     spin_lock_irqsave(&(dev->lock),f);
986
987     op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
988
989     spin_unlock_irqrestore(&(dev->lock),f);
990
991     return op_len;
992  }
993  
994  
995
996
997
998
999 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1000     .open                       = palacios_host_dev_open,
1001     .close                      = palacios_host_dev_close,
1002     .read_io                    = palacios_host_dev_read_io,
1003     .write_io                   = palacios_host_dev_write_io,
1004     .read_mem                   = palacios_host_dev_read_mem,
1005     .write_mem                  = palacios_host_dev_write_mem,
1006     .read_config                = palacios_host_dev_read_conf,
1007     .write_config               = palacios_host_dev_write_conf,
1008     .ack_irq                    = palacios_host_dev_ack_irq,
1009 };
1010
1011
1012
1013 int palacios_init_host_dev( void ) {
1014     V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1015     
1016     return 0;
1017 }