2 * Host device interface + user-space device interface
6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.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>
17 #include <interfaces/vmm_host_dev.h>
20 #include "iface-host-dev.h"
21 #include "linux-exts.h"
25 There are two things in this file:
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
33 Palacios opens a host device by issuing something like this:
35 palacios_host_dev_open( impl="user:foo" busclass=pci, opaque )
37 This will attempt to rendezvous with the user space device The
38 rendevzous retry and timeout periods can be set below.
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
44 The user space gets a file descriptor like this:
46 int vmfd = open("/dev/v3-vmX",...);
48 int devfd = ioctl(vmfd,V3_HOST_DEV_CONNECT,"user:foo");
50 This will attempt to rendezvous with the host side.
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.
57 struct palacios_host_dev_user_op op;
60 op.type = PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST;
63 ioctl(devfd, V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL, &op);
65 // return value is # bytes read or written; or 0 if irq injected
66 // negative value is error
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.
79 What this looks like is:
81 poll(...devfd for read...) or select(...devfd for read...)
83 if (devfd is marked readable) {
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
89 struct palacios_host_dev_host_request_response *req;
91 req = allocate req to be at least size bytes long
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
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
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
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.
115 struct palacios_host_dev {
117 struct list_head devs;
123 #define RENDEZVOUS_WAIT_SECS 60
124 #define RENDEZVOUS_RETRY_SECS 1
127 #define SHALLOW_DEBUG 0
130 #define DEEP_DEBUG_PRINT(fmt, args...) DEBUG((fmt), ##args)
132 #define DEEP_DEBUG_PRINT(fmt, args...)
136 #define SHALLOW_DEBUG_PRINT(fmt, args...) INFO((fmt), ##args)
138 #define SHALLOW_DEBUG_PRINT(fmt, args...)
142 struct palacios_host_device_user {
144 int connected; // is the user space connected to this?
145 int waiting; // am I waiting for a user-space response?
147 int fd; // what is the user space fd?
149 char url[MAX_URL]; // what is the url describing the device
151 v3_guest_dev_t guestdev; // what is the palacios-side device
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
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
160 struct list_head node; // for adding me to the list of hostdevs this VM has
164 /**************************************************************************************
166 *************************************************************************************/
168 static void palacios_host_dev_user_free(struct palacios_host_device_user *dev)
171 palacios_free(dev->req);
175 palacios_free(dev->resp);
183 // Is this structure big enough for the data_size we will use?
185 // THIS FUNCTION CAN BE CALLED WHILE INTERRUPTS ARE OFF
187 static int palacios_bigenough_reqresp(struct palacios_host_dev_host_request_response *r, uint64_t data_size)
192 if (((r->len)-sizeof(struct palacios_host_dev_host_request_response)) < data_size) {
201 // Resize a request/response structure so that it will fit data_size bytes
203 // At the end of this, *r->len >= sizeof(struct)+data_size
205 // THIS FUNCTION MAY SLEEP AS IT CALLS KMALLOC
206 // DO NOT CALL IT WHILE HOLDING A SPIN LOCK WITH INTERRUPTS OFF
208 static int palacios_resize_reqresp(struct palacios_host_dev_host_request_response **r, uint64_t data_size, int copy)
211 DEEP_DEBUG_PRINT("palacios: hostdev: resize 0x%p to %llu\n",*r,data_size);
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");
219 ERROR("palacios: hostdev: failed to allocate\n");
222 (*r)->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
223 DEEP_DEBUG_PRINT("palacios: hostdev: allocated\n");
227 //let it go if it's big enough
228 uint64_t cur_len = (*r)->len-sizeof(struct palacios_host_dev_host_request_response);
230 if (data_size<=cur_len) {
232 DEEP_DEBUG_PRINT("palacios: hostdev: size ok\n");
235 struct palacios_host_dev_host_request_response *new;
241 new = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
243 ERROR("palacios: hostdev: failed to reallocate\n");
246 new->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
248 memcpy(new->data,(*r)->data,(*r)->data_len-sizeof(struct palacios_host_dev_host_request_response));
249 new->data_len=(*r)->data_len;
253 DEEP_DEBUG_PRINT("palacios: hostdev: reallocated\n");
260 static void cycle_request_response(struct palacios_host_device_user *dev)
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) {}
268 DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response - done\n");
271 static void cycle_response_request(struct palacios_host_device_user *dev)
273 DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request\n");
275 wake_up_interruptible(&(dev->host_wait_queue));
276 DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request - done\n");
280 /*********************************************************************************************
282 Interface to user space
284 *********************************************************************************************/
288 static unsigned int host_dev_poll(struct file * filp,
289 struct poll_table_struct * poll_tb)
292 struct palacios_host_device_user * dev = filp->private_data;
295 SHALLOW_DEBUG_PRINT("palacios: hostdev: poll\n");
297 if (!dev->connected) {
298 ERROR("palcios: hostdev: poll on unconnected device\n");
302 palacios_spinlock_lock_irqsave(&(dev->lock),f);
305 // register ourselves on the user wait queue
306 poll_wait(filp, &(dev->user_wait_queue), poll_tb);
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;
315 // No request yet, so we need to wait for one to show up.
317 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
319 DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n");
320 // We will get called again when that queue is woken up
326 static int host_dev_release(struct inode * i, struct file * filp)
328 struct palacios_host_device_user *dev = filp->private_data;
331 INFO("palacios: user side is closing host device \"%s\"\n",dev->url);
333 palacios_spinlock_lock_irqsave(&(dev->lock), f);
335 palacios_spinlock_unlock_irqrestore(&(dev->lock), f);
337 // it is the palacios->host interface's responsibility to ignore
338 // reads/writes until connected is true
343 static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg)
345 void __user *argp = (void __user *)arg;
347 struct palacios_host_device_user *dev = fp->private_data;
349 DEEP_DEBUG_PRINT("palacios: hostdev: ioctl %u\n",val);
352 if (!dev->connected) {
353 ERROR("palacios: hostdev: ioctl on unconnected device\n");
358 case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
360 struct palacios_host_dev_user_op op;
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);
367 DEEP_DEBUG_PRINT("palacios: hostdev: user request push, type %d\n",op.type);
370 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
371 void *temp = palacios_alloc(op.len);
373 DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
376 ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
380 if (v3_host_dev_read_guest_mem(dev,
385 ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
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);
403 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
406 DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
408 temp = palacios_alloc(op.len);
411 ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
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);
421 if (v3_host_dev_write_guest_mem(dev,
426 ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
437 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
439 DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n");
441 return v3_host_dev_raise_irq(dev, dev->guestdev, op.irq);
446 ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url);
453 case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
458 DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
460 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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
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!
476 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
478 DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
480 return 1; // have request for you
486 case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
490 palacios_spinlock_lock_irqsave(&(dev->lock),f);
492 DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
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
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!
507 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
509 DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
511 return 1; // copied request for you
515 case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
518 uint64_t user_datalen;
521 palacios_spinlock_lock_irqsave(&(dev->lock),f);
523 DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
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!
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!
537 if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) {
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);
544 if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
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);
549 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
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);
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);
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!
573 dev->resp->len=old_len;
575 DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
576 // now have valid response!
579 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
581 // wake the palacios side up so that it sees it
582 cycle_response_request(dev);
589 ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
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,
605 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data)
607 void __user * argp = (void __user *)arg;
609 struct palacios_host_dev * host_dev = priv_data;
610 struct palacios_host_device_user *dev;
611 unsigned long f1, f2;
616 if (copy_from_user(url, argp, MAX_URL)) {
617 ERROR("copy from user error getting url for host device connect...\n");
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);
627 INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
629 // We will scan the list looking for the relevant
630 // URL. If we don't find it after a while, we give up
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)) {
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);
644 dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 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);
654 palacios_free(dev->req);
658 palacios_free(dev->resp);
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);
666 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
669 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
671 ssleep(RENDEZVOUS_RETRY_SECS);
674 ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
687 /***************************************************************************************
689 Following this is the implementation of the palacios->host interface
691 **************************************************************************************/
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)
700 if (dev->connected) {
705 INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
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);
715 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
716 ssleep(RENDEZVOUS_RETRY_SECS);
719 ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
721 // We stay in the list because a future rendezvous might happen
727 /* Creates the device without rendezvous */
728 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
731 void *host_priv_data)
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;
739 I will create the device in the list and then wait
740 for the user side to attach
748 host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
750 if (host_dev == NULL) {
751 ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
756 if (strncasecmp(url,"user:",5)) {
757 ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
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)) {
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);
771 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
774 INFO("palacios: creating host device \"%s\"\n",url);
776 dev = palacios_alloc(sizeof(struct palacios_host_device_user));
779 ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
783 memset(dev,0,sizeof(struct palacios_host_device_user));
785 strncpy(dev->url,url,MAX_URL);
787 dev->guestdev = gdev;
791 palacios_spinlock_init(&(dev->lock));
793 init_waitqueue_head(&(dev->user_wait_queue));
794 init_waitqueue_head(&(dev->host_wait_queue));
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);
801 INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
809 static int palacios_host_dev_close(v3_host_dev_t hostdev)
811 unsigned long f1, f2;
813 struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
814 struct palacios_host_dev * host_dev = NULL;
816 INFO("palacios: closing host device \"%s\"\n",dev->url);
818 if ((dev == NULL) || (dev->guest == NULL)) {
822 host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
825 if (host_dev == NULL) {
829 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
831 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
833 if (dev->connected) {
835 // After this, any user side request will return -EFAULT
838 list_del(&(dev->node));
840 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
841 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
843 palacios_spinlock_deinit(&(dev->lock));
845 palacios_host_dev_user_free(dev);
853 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
858 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
862 DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
865 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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);
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);
881 // resize request (no data)
882 if (!palacios_bigenough_reqresp(dev->req,0)) {
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);
887 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
889 if (palacios_resize_reqresp(&(dev->req),0,0)) {
890 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
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);
902 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
904 dev->req->op_len=len;
906 dev->req->conf_addr=0;
907 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
911 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
913 // hand over to the user space and wait for it to respond
914 cycle_request_response(dev);
916 // We're back! So now we'll hand the response back to Palacios
918 palacios_spinlock_lock_irqsave(&(dev->lock),f);
920 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
922 memcpy(dest,dev->resp->data, op_len);
924 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
929 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
934 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
938 DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa);
940 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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);
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);
954 // resize request (no data)
955 if (!palacios_bigenough_reqresp(dev->req,0)) {
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);
960 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
962 if (palacios_resize_reqresp(&(dev->req),0,0)) {
963 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
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);
974 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
976 dev->req->op_len=len;
978 dev->req->conf_addr=0;
979 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
983 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
985 // hand over to the user space and wait for it to respond
986 cycle_request_response(dev);
988 // We're back! So now we'll hand the response back to Palacios
990 palacios_spinlock_lock_irqsave(&(dev->lock),f);
992 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
994 memcpy(dest,dev->resp->data, op_len);
996 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1001 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
1006 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1010 DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
1012 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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);
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);
1026 // resize request (no data)
1027 if (!palacios_bigenough_reqresp(dev->req,0)) {
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);
1032 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1034 if (palacios_resize_reqresp(&(dev->req),0,0)) {
1035 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
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);
1046 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1048 dev->req->op_len=len;
1050 dev->req->conf_addr=offset;
1051 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1055 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1057 // hand over to the user space and wait for it to respond
1058 cycle_request_response(dev);
1060 // We're back! So now we'll hand the response back to Palacios
1062 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1064 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1066 memcpy(dest,dev->resp->data, op_len);
1068 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1074 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1079 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1083 DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1085 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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);
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);
1100 if (!palacios_bigenough_reqresp(dev->req,len)) {
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);
1105 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1107 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1108 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
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);
1119 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1120 dev->req->port=port;
1121 dev->req->op_len=len;
1123 dev->req->conf_addr=0;
1124 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1126 memcpy(dev->req->data,src,len);
1130 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1132 // hand over to the user space and wait for it to respond
1133 cycle_request_response(dev);
1135 // We're back! So now we'll hand the response back to Palacios
1137 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1139 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1141 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1147 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1152 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1156 DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1158 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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);
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);
1173 if (!palacios_bigenough_reqresp(dev->req,len)) {
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);
1178 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1180 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1181 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
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);
1192 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1194 dev->req->op_len=len;
1196 dev->req->conf_addr=0;
1197 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1199 memcpy(dev->req->data,src,len);
1203 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1205 // hand over to the user space and wait for it to respond
1206 cycle_request_response(dev);
1208 // We're back! So now we'll hand the response back to Palacios
1210 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1212 op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1214 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1222 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1227 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1231 DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1233 palacios_spinlock_lock_irqsave(&(dev->lock),f);
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);
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);
1248 if (!palacios_bigenough_reqresp(dev->req,len)) {
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);
1253 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1255 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1256 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
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);
1267 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1269 dev->req->op_len=len;
1271 dev->req->conf_addr=offset;
1272 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1274 memcpy(dev->req->data,src,len);
1278 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1280 // hand over to the user space and wait for it to respond
1281 cycle_request_response(dev);
1283 // We're back! So now we'll hand the response back to Palacios
1285 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1287 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1289 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1295 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
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,
1319 static int host_dev_init( void ) {
1320 V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1326 static int host_dev_deinit(void) {
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));
1335 ERROR("palacios: failed to do guest_init for host device\n");
1340 INIT_LIST_HEAD(&(host_dev->devs));
1341 palacios_spinlock_init(&(host_dev->lock));
1343 *vm_data = host_dev;
1346 add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1352 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1354 struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1355 palacios_spinlock_deinit(&(host_dev->lock));
1356 palacios_free(host_dev);
1363 static struct linux_ext host_dev_ext = {
1364 .name = "HOST_DEVICE_INTERFACE",
1365 .init = host_dev_init,
1366 .deinit = host_dev_deinit,
1367 .guest_init = host_dev_guest_init,
1368 .guest_deinit = host_dev_guest_deinit
1372 register_extension(&host_dev_ext);