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 // Yes, we have a request if you want it!
306 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
307 DEEP_DEBUG_PRINT("palacios: hostdev: poll done immediate\n");
308 return POLLIN | POLLRDNORM;
311 // No request yet, so we need to wait for one to show up.
313 // register ourselves on the user wait queue
314 poll_wait(filp, &(dev->user_wait_queue), poll_tb);
316 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
318 DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n");
319 // We will get called again when that queue is woken up
325 static int host_dev_release(struct inode * i, struct file * filp)
327 struct palacios_host_device_user *dev = filp->private_data;
330 INFO("palacios: user side is closing host device \"%s\"\n",dev->url);
332 palacios_spinlock_lock_irqsave(&(dev->lock), f);
334 palacios_spinlock_unlock_irqrestore(&(dev->lock), f);
336 // it is the palacios->host interface's responsibility to ignore
337 // reads/writes until connected is true
342 static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg)
344 void __user *argp = (void __user *)arg;
346 struct palacios_host_device_user *dev = fp->private_data;
348 DEEP_DEBUG_PRINT("palacios: hostdev: ioctl %u\n",val);
351 if (!dev->connected) {
352 ERROR("palacios: hostdev: ioctl on unconnected device\n");
357 case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
359 struct palacios_host_dev_user_op op;
361 if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) {
362 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
366 DEEP_DEBUG_PRINT("palacios: hostdev: user request push, type %d\n",op.type);
369 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
370 void *temp = palacios_alloc(op.len);
372 DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
375 ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
379 if (v3_host_dev_read_guest_mem(dev,
384 ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
389 if (copy_to_user(op.data,temp,op.len)) {
390 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
402 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
405 DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
407 temp = palacios_alloc(op.len);
410 ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
414 if (copy_from_user(temp,op.data,op.len)) {
415 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
420 if (v3_host_dev_write_guest_mem(dev,
425 ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
436 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: {
438 DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n");
440 return v3_host_dev_raise_irq(dev, dev->guestdev, op.irq);
445 ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url);
452 case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
457 DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
459 palacios_spinlock_lock_irqsave(&(dev->lock),f);
461 if (!(dev->waiting)) {
462 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
463 DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n");
464 schedule(); // avoid livelock for polling user space process SUSPICOUS
465 return 0; // no request available now
468 if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) {
469 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
470 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
471 return -EFAULT; // failed to copy!
475 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
477 DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
479 return 1; // have request for you
485 case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
489 palacios_spinlock_lock_irqsave(&(dev->lock),f);
491 DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
493 if (!(dev->waiting) || !(dev->req)) {
494 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
495 DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
496 return 0; // no request available now
500 if (copy_to_user(argp,dev->req,dev->req->data_len)) {
501 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
502 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
503 return -EFAULT; // failed to copy!
506 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
508 DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
510 return 1; // copied request for you
514 case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
517 uint64_t user_datalen;
520 palacios_spinlock_lock_irqsave(&(dev->lock),f);
522 DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
524 if (!(dev->waiting)) {
525 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
526 ERROR("palacios: hostdev: no matching request for pushed response\n");
527 return 0; // no request outstanding, so we do not need a response!
530 if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) {
531 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
532 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
533 return -EFAULT; // failed to copy!
536 if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) {
538 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
539 ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
543 if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
545 // we drop the lock, turn on interrupts, resize, and then retry
546 DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
548 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
550 if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
551 ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
554 // reacquire the lock
555 // There shouldn't be a race here, since there should
556 // be exactly one user space thread giving us a response for this device
557 // and it is blocked waiting for us to finish
558 palacios_spinlock_lock_irqsave(&(dev->lock),f);
559 DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url);
563 //We only copy data_len bytes from user, but we will
564 //overwrite the len field, so we preserve and then restore
565 old_len = dev->resp->len;
566 if (copy_from_user(dev->resp, argp, user_datalen)) {
567 dev->resp->len=old_len;
568 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
569 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
570 return -EFAULT; // failed to copy!
572 dev->resp->len=old_len;
574 DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
575 // now have valid response!
578 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
580 // wake the palacios side up so that it sees it
581 cycle_response_request(dev);
588 ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
595 static struct file_operations host_dev_fops = {
596 .poll = host_dev_poll,
597 .release = host_dev_release,
598 .compat_ioctl = host_dev_ioctl,
599 .unlocked_ioctl = host_dev_ioctl,
604 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data)
606 void __user * argp = (void __user *)arg;
608 struct palacios_host_dev * host_dev = priv_data;
609 struct palacios_host_device_user *dev;
610 unsigned long f1, f2;
615 if (copy_from_user(url, argp, MAX_URL)) {
616 ERROR("copy from user error getting url for host device connect...\n");
620 // currently only support user: types:
621 if (strncasecmp(url,"user:",5)) {
622 ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
626 INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
628 // We will scan the list looking for the relevant
629 // URL. If we don't find it after a while, we give up
631 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
632 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
633 list_for_each_entry(dev,&(host_dev->devs), node) {
634 if (!strncasecmp(url,dev->url,MAX_URL)) {
636 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
637 if (dev->connected) {
638 ERROR("palacios: device for \"%s\" is already connected!\n",url);
639 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
640 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
643 dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
645 ERROR("palacios: cannot create fd for device \"%s\"\n",url);
646 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
647 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
653 palacios_free(dev->req);
657 palacios_free(dev->resp);
660 INFO("palacios: connected fd for device \"%s\"\n",url);
661 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
662 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
665 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
668 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
670 ssleep(RENDEZVOUS_RETRY_SECS);
673 ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
686 /***************************************************************************************
688 Following this is the implementation of the palacios->host interface
690 **************************************************************************************/
693 /* Attempt to rendezvous with the user device if no device is currently connected */
694 static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
699 if (dev->connected) {
704 INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
706 // Now wait until we are noticed!
707 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
708 palacios_spinlock_lock_irqsave(&(dev->lock),f);
709 if (dev->connected) {
710 INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
711 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
714 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
715 ssleep(RENDEZVOUS_RETRY_SECS);
718 ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
720 // We stay in the list because a future rendezvous might happen
726 /* Creates the device without rendezvous */
727 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
730 void *host_priv_data)
732 struct v3_guest *guest= (struct v3_guest*)host_priv_data;
733 struct palacios_host_device_user *dev;
734 struct palacios_host_dev * host_dev = NULL;
738 I will create the device in the list and then wait
739 for the user side to attach
747 host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
749 if (host_dev == NULL) {
750 ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
755 if (strncasecmp(url,"user:",5)) {
756 ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
760 // Check to see if a device of this url already exists, which would be ugly
761 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
762 list_for_each_entry(dev,&(host_dev->devs), node) {
763 if (!strncasecmp(url,dev->url,MAX_URL)) {
765 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
766 ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
770 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
773 INFO("palacios: creating host device \"%s\"\n",url);
775 dev = palacios_alloc(sizeof(struct palacios_host_device_user));
778 ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
782 memset(dev,0,sizeof(struct palacios_host_device_user));
784 strncpy(dev->url,url,MAX_URL);
786 dev->guestdev = gdev;
790 palacios_spinlock_init(&(dev->lock));
792 init_waitqueue_head(&(dev->user_wait_queue));
793 init_waitqueue_head(&(dev->host_wait_queue));
795 // Insert ourselves into the list
796 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
797 list_add(&(dev->node),&(host_dev->devs));
798 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
800 INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
808 static int palacios_host_dev_close(v3_host_dev_t hostdev)
810 unsigned long f1, f2;
812 struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
813 struct palacios_host_dev * host_dev = NULL;
815 INFO("palacios: closing host device \"%s\"\n",dev->url);
817 if ((dev == NULL) || (dev->guest == NULL)) {
821 host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
824 if (host_dev == NULL) {
828 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
830 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
832 if (dev->connected) {
834 // After this, any user side request will return -EFAULT
837 list_del(&(dev->node));
839 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
840 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
842 palacios_spinlock_deinit(&(dev->lock));
844 palacios_host_dev_user_free(dev);
852 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
857 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
861 DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
864 palacios_spinlock_lock_irqsave(&(dev->lock),f);
866 if (palacios_host_dev_rendezvous(dev)) {
867 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
868 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
873 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
874 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);
880 // resize request (no data)
881 if (!palacios_bigenough_reqresp(dev->req,0)) {
883 // we drop the lock, turn on interrupts, resize, and then retry
884 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
886 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
888 if (palacios_resize_reqresp(&(dev->req),0,0)) {
889 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
892 // reacquire the lock
893 // There shouldn't be a race here since there should not be another
894 // request from palacios until this one finishes
895 palacios_spinlock_lock_irqsave(&(dev->lock),f);
896 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
901 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
903 dev->req->op_len=len;
905 dev->req->conf_addr=0;
906 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
910 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
912 // hand over to the user space and wait for it to respond
913 cycle_request_response(dev);
915 // We're back! So now we'll hand the response back to Palacios
917 palacios_spinlock_lock_irqsave(&(dev->lock),f);
919 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
921 memcpy(dest,dev->resp->data, op_len);
923 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
928 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
933 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
937 DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa);
939 palacios_spinlock_lock_irqsave(&(dev->lock),f);
941 if (palacios_host_dev_rendezvous(dev)) {
942 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
943 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
948 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
949 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);
953 // resize request (no data)
954 if (!palacios_bigenough_reqresp(dev->req,0)) {
956 // we drop the lock, turn on interrupts, resize, and then retry
957 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
959 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
961 if (palacios_resize_reqresp(&(dev->req),0,0)) {
962 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
965 // reacquire the lock
966 // There shouldn't be a race here since there should not be another
967 // request from palacios until this one finishes
968 palacios_spinlock_lock_irqsave(&(dev->lock),f);
969 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
973 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
975 dev->req->op_len=len;
977 dev->req->conf_addr=0;
978 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
982 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
984 // hand over to the user space and wait for it to respond
985 cycle_request_response(dev);
987 // We're back! So now we'll hand the response back to Palacios
989 palacios_spinlock_lock_irqsave(&(dev->lock),f);
991 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
993 memcpy(dest,dev->resp->data, op_len);
995 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1000 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
1005 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1009 DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
1011 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1013 if (palacios_host_dev_rendezvous(dev)) {
1014 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1015 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1020 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1021 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);
1025 // resize request (no data)
1026 if (!palacios_bigenough_reqresp(dev->req,0)) {
1028 // we drop the lock, turn on interrupts, resize, and then retry
1029 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1031 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1033 if (palacios_resize_reqresp(&(dev->req),0,0)) {
1034 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1037 // reacquire the lock
1038 // There shouldn't be a race here since there should not be another
1039 // request from palacios until this one finishes
1040 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1041 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1045 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1047 dev->req->op_len=len;
1049 dev->req->conf_addr=offset;
1050 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1054 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1056 // hand over to the user space and wait for it to respond
1057 cycle_request_response(dev);
1059 // We're back! So now we'll hand the response back to Palacios
1061 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1063 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1065 memcpy(dest,dev->resp->data, op_len);
1067 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1073 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1078 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1082 DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1084 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1086 if (palacios_host_dev_rendezvous(dev)) {
1087 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1088 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1093 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1094 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);
1099 if (!palacios_bigenough_reqresp(dev->req,len)) {
1101 // we drop the lock, turn on interrupts, resize, and then retry
1102 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1104 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1106 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1107 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1110 // reacquire the lock
1111 // There shouldn't be a race here since there should not be another
1112 // request from palacios until this one finishes
1113 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1114 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1118 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1119 dev->req->port=port;
1120 dev->req->op_len=len;
1122 dev->req->conf_addr=0;
1123 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1125 memcpy(dev->req->data,src,len);
1129 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1131 // hand over to the user space and wait for it to respond
1132 cycle_request_response(dev);
1134 // We're back! So now we'll hand the response back to Palacios
1136 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1138 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1140 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1146 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1151 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1155 DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1157 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1159 if (palacios_host_dev_rendezvous(dev)) {
1160 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1161 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1166 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1167 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);
1172 if (!palacios_bigenough_reqresp(dev->req,len)) {
1174 // we drop the lock, turn on interrupts, resize, and then retry
1175 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1177 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1179 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1180 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1183 // reacquire the lock
1184 // There shouldn't be a race here since there should not be another
1185 // request from palacios until this one finishes
1186 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1187 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1191 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1193 dev->req->op_len=len;
1195 dev->req->conf_addr=0;
1196 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1198 memcpy(dev->req->data,src,len);
1202 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1204 // hand over to the user space and wait for it to respond
1205 cycle_request_response(dev);
1207 // We're back! So now we'll hand the response back to Palacios
1209 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1211 op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1213 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1221 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1226 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1230 DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1232 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1234 if (palacios_host_dev_rendezvous(dev)) {
1235 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1236 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1241 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1242 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);
1247 if (!palacios_bigenough_reqresp(dev->req,len)) {
1249 // we drop the lock, turn on interrupts, resize, and then retry
1250 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1252 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1254 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1255 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1258 // reacquire the lock
1259 // There shouldn't be a race here since there should not be another
1260 // request from palacios until this one finishes
1261 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1262 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1266 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1268 dev->req->op_len=len;
1270 dev->req->conf_addr=offset;
1271 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1273 memcpy(dev->req->data,src,len);
1277 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1279 // hand over to the user space and wait for it to respond
1280 cycle_request_response(dev);
1282 // We're back! So now we'll hand the response back to Palacios
1284 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1286 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1288 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1294 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1304 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1305 .open = palacios_host_dev_open_deferred,
1306 .close = palacios_host_dev_close,
1307 .read_io = palacios_host_dev_read_io,
1308 .write_io = palacios_host_dev_write_io,
1309 .read_mem = palacios_host_dev_read_mem,
1310 .write_mem = palacios_host_dev_write_mem,
1311 .read_config = palacios_host_dev_read_conf,
1312 .write_config = palacios_host_dev_write_conf,
1313 .ack_irq = palacios_host_dev_ack_irq,
1318 static int host_dev_init( void ) {
1319 V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1325 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1326 struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1329 ERROR("palacios: failed to do guest_init for host device\n");
1334 INIT_LIST_HEAD(&(host_dev->devs));
1335 palacios_spinlock_init(&(host_dev->lock));
1337 *vm_data = host_dev;
1340 add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1346 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1348 struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1349 palacios_spinlock_deinit(&(host_dev->lock));
1350 palacios_free(host_dev);
1357 static struct linux_ext host_dev_ext = {
1358 .name = "HOST_DEVICE_INTERFACE",
1359 .init = host_dev_init,
1361 .guest_init = host_dev_guest_init,
1362 .guest_deinit = host_dev_guest_deinit
1366 register_extension(&host_dev_ext);