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
152 v3_guest_dev_intr_t guestintr; // what is the palacios-side device interrupt info
154 wait_queue_head_t user_wait_queue; // user space processes waiting on us (should be only one)
155 wait_queue_head_t host_wait_queue; // host threads (should only be one) waiting on user space
157 struct v3_guest *guest; // my guest
158 struct palacios_host_dev_host_request_response *req; // curent request
159 struct palacios_host_dev_host_request_response *resp; // curent response
161 struct list_head node; // for adding me to the list of hostdevs this VM has
165 /**************************************************************************************
167 *************************************************************************************/
169 static void palacios_host_dev_user_free(struct palacios_host_device_user *dev)
172 palacios_free(dev->req);
176 palacios_free(dev->resp);
184 // Is this structure big enough for the data_size we will use?
186 // THIS FUNCTION CAN BE CALLED WHILE INTERRUPTS ARE OFF
188 static int palacios_bigenough_reqresp(struct palacios_host_dev_host_request_response *r, uint64_t data_size)
193 if (((r->len)-sizeof(struct palacios_host_dev_host_request_response)) < data_size) {
202 // Resize a request/response structure so that it will fit data_size bytes
204 // At the end of this, *r->len >= sizeof(struct)+data_size
206 // THIS FUNCTION MAY SLEEP AS IT CALLS KMALLOC
207 // DO NOT CALL IT WHILE HOLDING A SPIN LOCK WITH INTERRUPTS OFF
209 static int palacios_resize_reqresp(struct palacios_host_dev_host_request_response **r, uint64_t data_size, int copy)
212 DEEP_DEBUG_PRINT("palacios: hostdev: resize 0x%p to %llu\n",*r,data_size);
216 DEEP_DEBUG_PRINT("palacios: hostdev: attempt alloc\n");
217 *r = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
218 DEEP_DEBUG_PRINT("palacios: hostdev: palacios_alloc done\n");
220 ERROR("palacios: hostdev: failed to allocate\n");
223 (*r)->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
224 DEEP_DEBUG_PRINT("palacios: hostdev: allocated\n");
228 //let it go if it's big enough
229 uint64_t cur_len = (*r)->len-sizeof(struct palacios_host_dev_host_request_response);
231 if (data_size<=cur_len) {
233 DEEP_DEBUG_PRINT("palacios: hostdev: size ok\n");
236 struct palacios_host_dev_host_request_response *new;
242 new = palacios_alloc(sizeof(struct palacios_host_dev_host_request_response)+data_size);
244 ERROR("palacios: hostdev: failed to reallocate\n");
247 new->len=sizeof(struct palacios_host_dev_host_request_response)+data_size;
249 memcpy(new->data,(*r)->data,(*r)->data_len-sizeof(struct palacios_host_dev_host_request_response));
250 new->data_len=(*r)->data_len;
254 DEEP_DEBUG_PRINT("palacios: hostdev: reallocated\n");
261 static void cycle_request_response(struct palacios_host_device_user *dev)
263 DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response\n");
264 // wake up user side so that polls fall through
265 wake_up_interruptible(&(dev->user_wait_queue));
266 // put us to sleep until the user side wakes us up
267 while (wait_event_interruptible((dev->host_wait_queue), (dev->waiting==0)) != 0) {}
269 DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response - done\n");
272 static void cycle_response_request(struct palacios_host_device_user *dev)
274 DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request\n");
276 wake_up_interruptible(&(dev->host_wait_queue));
277 DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request - done\n");
281 /*********************************************************************************************
283 Interface to user space
285 *********************************************************************************************/
289 static unsigned int host_dev_poll(struct file * filp,
290 struct poll_table_struct * poll_tb)
293 struct palacios_host_device_user * dev = filp->private_data;
296 SHALLOW_DEBUG_PRINT("palacios: hostdev: poll\n");
298 if (!dev->connected) {
299 ERROR("palcios: hostdev: poll on unconnected device\n");
303 palacios_spinlock_lock_irqsave(&(dev->lock),f);
306 // register ourselves on the user wait queue
307 poll_wait(filp, &(dev->user_wait_queue), poll_tb);
310 // Yes, we have a request if you want it!
311 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
312 DEEP_DEBUG_PRINT("palacios: hostdev: poll done immediate\n");
313 return POLLIN | POLLRDNORM;
316 // No request yet, so we need to wait for one to show up.
318 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
320 DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n");
321 // We will get called again when that queue is woken up
327 static int host_dev_release(struct inode * i, struct file * filp)
329 struct palacios_host_device_user *dev = filp->private_data;
332 INFO("palacios: user side is closing host device \"%s\"\n",dev->url);
334 palacios_spinlock_lock_irqsave(&(dev->lock), f);
336 palacios_spinlock_unlock_irqrestore(&(dev->lock), f);
338 // it is the palacios->host interface's responsibility to ignore
339 // reads/writes until connected is true
344 static long host_dev_ioctl(struct file * fp, unsigned int val, unsigned long arg)
346 void __user *argp = (void __user *)arg;
348 struct palacios_host_device_user *dev = fp->private_data;
350 DEEP_DEBUG_PRINT("palacios: hostdev: ioctl %u\n",val);
353 if (!dev->connected) {
354 ERROR("palacios: hostdev: ioctl on unconnected device\n");
359 case V3_HOST_DEV_USER_REQUEST_PUSH_IOCTL: {
361 struct palacios_host_dev_user_op op;
363 if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) {
364 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
368 DEEP_DEBUG_PRINT("palacios: hostdev: user request push, type %d\n",op.type);
371 case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: {
372 void *temp = palacios_alloc(op.len);
374 DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
377 ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
381 if (v3_host_dev_read_guest_mem(dev,
386 ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
391 if (copy_to_user(op.data,temp,op.len)) {
392 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
404 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
407 DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
409 temp = palacios_alloc(op.len);
412 ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
416 if (copy_from_user(temp,op.data,op.len)) {
417 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
422 if (v3_host_dev_write_guest_mem(dev,
427 ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
438 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST: {
440 DEEP_DEBUG_PRINT("palacios: hostdev: irq raise guest\n");
442 return v3_host_dev_raise_irq(dev, dev->guestdev, dev->guestintr, op.irq);
445 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST: {
447 DEEP_DEBUG_PRINT("palacios: hostdev: irq lower guest\n");
449 return v3_host_dev_lower_irq(dev, dev->guestdev, dev->guestintr, op.irq);
454 ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url);
461 case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
466 DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
468 palacios_spinlock_lock_irqsave(&(dev->lock),f);
470 if (!(dev->waiting)) {
471 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
472 DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n");
473 schedule(); // avoid livelock for polling user space process SUSPICOUS
474 return 0; // no request available now
477 if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) {
478 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
479 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
480 return -EFAULT; // failed to copy!
484 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
486 DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
488 return 1; // have request for you
494 case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
498 palacios_spinlock_lock_irqsave(&(dev->lock),f);
500 DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
502 if (!(dev->waiting) || !(dev->req)) {
503 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
504 DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
505 return 0; // no request available now
509 if (copy_to_user(argp,dev->req,dev->req->data_len)) {
510 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
511 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
512 return -EFAULT; // failed to copy!
515 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
517 DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
519 return 1; // copied request for you
523 case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
526 uint64_t user_datalen;
529 palacios_spinlock_lock_irqsave(&(dev->lock),f);
531 DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
533 if (!(dev->waiting)) {
534 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
535 ERROR("palacios: hostdev: no matching request for pushed response\n");
536 return 0; // no request outstanding, so we do not need a response!
539 if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) {
540 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
541 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
542 return -EFAULT; // failed to copy!
545 if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) {
547 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
548 ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
552 if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
554 // we drop the lock, turn on interrupts, resize, and then retry
555 DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
557 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
559 if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
560 ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
563 // reacquire the lock
564 // There shouldn't be a race here, since there should
565 // be exactly one user space thread giving us a response for this device
566 // and it is blocked waiting for us to finish
567 palacios_spinlock_lock_irqsave(&(dev->lock),f);
568 DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url);
572 //We only copy data_len bytes from user, but we will
573 //overwrite the len field, so we preserve and then restore
574 old_len = dev->resp->len;
575 if (copy_from_user(dev->resp, argp, user_datalen)) {
576 dev->resp->len=old_len;
577 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
578 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
579 return -EFAULT; // failed to copy!
581 dev->resp->len=old_len;
583 DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
584 // now have valid response!
587 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
589 // wake the palacios side up so that it sees it
590 cycle_response_request(dev);
597 ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
604 static struct file_operations host_dev_fops = {
605 .poll = host_dev_poll,
606 .release = host_dev_release,
607 .compat_ioctl = host_dev_ioctl,
608 .unlocked_ioctl = host_dev_ioctl,
613 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data)
615 void __user * argp = (void __user *)arg;
617 struct palacios_host_dev * host_dev = priv_data;
618 struct palacios_host_device_user *dev;
619 unsigned long f1, f2;
624 if (copy_from_user(url, argp, MAX_URL)) {
625 ERROR("copy from user error getting url for host device connect...\n");
629 // currently only support user: types:
630 if (strncasecmp(url,"user:",5)) {
631 ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
635 INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
637 // We will scan the list looking for the relevant
638 // URL. If we don't find it after a while, we give up
640 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
641 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
642 list_for_each_entry(dev,&(host_dev->devs), node) {
643 if (!strncasecmp(url,dev->url,MAX_URL)) {
645 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
646 if (dev->connected) {
647 ERROR("palacios: device for \"%s\" is already connected!\n",url);
648 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
649 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
652 dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
654 ERROR("palacios: cannot create fd for device \"%s\"\n",url);
655 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
656 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
662 palacios_free(dev->req);
666 palacios_free(dev->resp);
669 INFO("palacios: connected fd for device \"%s\"\n",url);
670 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
671 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
674 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
677 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
679 ssleep(RENDEZVOUS_RETRY_SECS);
682 ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
695 /***************************************************************************************
697 Following this is the implementation of the palacios->host interface
699 **************************************************************************************/
702 /* Attempt to rendezvous with the user device if no device is currently connected */
703 static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
708 if (dev->connected) {
713 INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
715 // Now wait until we are noticed!
716 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
717 palacios_spinlock_lock_irqsave(&(dev->lock),f);
718 if (dev->connected) {
719 INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
720 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
723 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
724 ssleep(RENDEZVOUS_RETRY_SECS);
727 ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
729 // We stay in the list because a future rendezvous might happen
735 /* Creates the device without rendezvous */
736 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
739 v3_guest_dev_intr_t gintr,
740 void *host_priv_data)
742 struct v3_guest *guest= (struct v3_guest*)host_priv_data;
743 struct palacios_host_device_user *dev;
744 struct palacios_host_dev * host_dev = NULL;
748 I will create the device in the list and then wait
749 for the user side to attach
757 host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
759 if (host_dev == NULL) {
760 ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
765 if (strncasecmp(url,"user:",5)) {
766 ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
770 // Check to see if a device of this url already exists, which would be ugly
771 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
772 list_for_each_entry(dev,&(host_dev->devs), node) {
773 if (!strncasecmp(url,dev->url,MAX_URL)) {
775 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
776 ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
780 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
783 INFO("palacios: creating host device \"%s\"\n",url);
785 dev = palacios_alloc(sizeof(struct palacios_host_device_user));
788 ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
792 memset(dev,0,sizeof(struct palacios_host_device_user));
794 strncpy(dev->url,url,MAX_URL);
796 dev->guestdev = gdev;
798 dev->guestintr = gintr;
802 palacios_spinlock_init(&(dev->lock));
804 init_waitqueue_head(&(dev->user_wait_queue));
805 init_waitqueue_head(&(dev->host_wait_queue));
807 // Insert ourselves into the list
808 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
809 list_add(&(dev->node),&(host_dev->devs));
810 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
812 INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
820 static int palacios_host_dev_close(v3_host_dev_t hostdev)
822 unsigned long f1, f2;
824 struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
825 struct palacios_host_dev * host_dev = NULL;
827 INFO("palacios: closing host device \"%s\"\n",dev->url);
829 if ((dev == NULL) || (dev->guest == NULL)) {
833 host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
836 if (host_dev == NULL) {
840 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
842 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
844 if (dev->connected) {
846 // After this, any user side request will return -EFAULT
849 list_del(&(dev->node));
851 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
852 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
854 palacios_spinlock_deinit(&(dev->lock));
856 palacios_host_dev_user_free(dev);
864 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
869 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
873 DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
876 palacios_spinlock_lock_irqsave(&(dev->lock),f);
878 if (palacios_host_dev_rendezvous(dev)) {
879 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
880 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
885 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
886 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);
892 // resize request (no data)
893 if (!palacios_bigenough_reqresp(dev->req,0)) {
895 // we drop the lock, turn on interrupts, resize, and then retry
896 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
898 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
900 if (palacios_resize_reqresp(&(dev->req),0,0)) {
901 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
904 // reacquire the lock
905 // There shouldn't be a race here since there should not be another
906 // request from palacios until this one finishes
907 palacios_spinlock_lock_irqsave(&(dev->lock),f);
908 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
913 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
915 dev->req->op_len=len;
917 dev->req->conf_addr=0;
918 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
922 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
924 // hand over to the user space and wait for it to respond
925 cycle_request_response(dev);
927 // We're back! So now we'll hand the response back to Palacios
929 palacios_spinlock_lock_irqsave(&(dev->lock),f);
931 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
933 memcpy(dest,dev->resp->data, op_len);
935 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
940 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
945 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
949 DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa);
951 palacios_spinlock_lock_irqsave(&(dev->lock),f);
953 if (palacios_host_dev_rendezvous(dev)) {
954 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
955 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
960 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
961 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);
965 // resize request (no data)
966 if (!palacios_bigenough_reqresp(dev->req,0)) {
968 // we drop the lock, turn on interrupts, resize, and then retry
969 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
971 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
973 if (palacios_resize_reqresp(&(dev->req),0,0)) {
974 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
977 // reacquire the lock
978 // There shouldn't be a race here since there should not be another
979 // request from palacios until this one finishes
980 palacios_spinlock_lock_irqsave(&(dev->lock),f);
981 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
985 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
987 dev->req->op_len=len;
989 dev->req->conf_addr=0;
990 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
994 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
996 // hand over to the user space and wait for it to respond
997 cycle_request_response(dev);
999 // We're back! So now we'll hand the response back to Palacios
1001 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1003 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1005 memcpy(dest,dev->resp->data, op_len);
1007 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1012 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
1017 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1021 DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset);
1023 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1025 if (palacios_host_dev_rendezvous(dev)) {
1026 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1027 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1032 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1033 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);
1037 // resize request (no data)
1038 if (!palacios_bigenough_reqresp(dev->req,0)) {
1040 // we drop the lock, turn on interrupts, resize, and then retry
1041 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1043 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1045 if (palacios_resize_reqresp(&(dev->req),0,0)) {
1046 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1049 // reacquire the lock
1050 // There shouldn't be a race here since there should not be another
1051 // request from palacios until this one finishes
1052 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1053 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1057 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1059 dev->req->op_len=len;
1061 dev->req->conf_addr=offset;
1062 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1066 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1068 // hand over to the user space and wait for it to respond
1069 cycle_request_response(dev);
1071 // We're back! So now we'll hand the response back to Palacios
1073 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1075 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1077 memcpy(dest,dev->resp->data, op_len);
1079 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1085 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1090 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1094 DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1096 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1098 if (palacios_host_dev_rendezvous(dev)) {
1099 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1100 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1105 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1106 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);
1111 if (!palacios_bigenough_reqresp(dev->req,len)) {
1113 // we drop the lock, turn on interrupts, resize, and then retry
1114 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1116 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1118 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1119 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1122 // reacquire the lock
1123 // There shouldn't be a race here since there should not be another
1124 // request from palacios until this one finishes
1125 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1126 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1130 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1131 dev->req->port=port;
1132 dev->req->op_len=len;
1134 dev->req->conf_addr=0;
1135 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1137 memcpy(dev->req->data,src,len);
1141 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1143 // hand over to the user space and wait for it to respond
1144 cycle_request_response(dev);
1146 // We're back! So now we'll hand the response back to Palacios
1148 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1150 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1152 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1158 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1163 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1167 DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1169 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1171 if (palacios_host_dev_rendezvous(dev)) {
1172 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1173 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1178 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1179 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);
1184 if (!palacios_bigenough_reqresp(dev->req,len)) {
1186 // we drop the lock, turn on interrupts, resize, and then retry
1187 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1189 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1191 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1192 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1195 // reacquire the lock
1196 // There shouldn't be a race here since there should not be another
1197 // request from palacios until this one finishes
1198 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1199 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1203 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1205 dev->req->op_len=len;
1207 dev->req->conf_addr=0;
1208 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1210 memcpy(dev->req->data,src,len);
1214 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1216 // hand over to the user space and wait for it to respond
1217 cycle_request_response(dev);
1219 // We're back! So now we'll hand the response back to Palacios
1221 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1223 op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1225 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1233 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1238 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1242 DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1244 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1246 if (palacios_host_dev_rendezvous(dev)) {
1247 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1248 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1253 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1254 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);
1259 if (!palacios_bigenough_reqresp(dev->req,len)) {
1261 // we drop the lock, turn on interrupts, resize, and then retry
1262 DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url);
1264 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1266 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1267 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1270 // reacquire the lock
1271 // There shouldn't be a race here since there should not be another
1272 // request from palacios until this one finishes
1273 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1274 DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url);
1278 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1280 dev->req->op_len=len;
1282 dev->req->conf_addr=offset;
1283 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1285 memcpy(dev->req->data,src,len);
1289 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1291 // hand over to the user space and wait for it to respond
1292 cycle_request_response(dev);
1294 // We're back! So now we'll hand the response back to Palacios
1296 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1298 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1300 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1306 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1316 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1317 .open = palacios_host_dev_open_deferred,
1318 .close = palacios_host_dev_close,
1319 .read_io = palacios_host_dev_read_io,
1320 .write_io = palacios_host_dev_write_io,
1321 .read_mem = palacios_host_dev_read_mem,
1322 .write_mem = palacios_host_dev_write_mem,
1323 .read_config = palacios_host_dev_read_conf,
1324 .write_config = palacios_host_dev_write_conf,
1325 .ack_irq = palacios_host_dev_ack_irq,
1330 static int host_dev_init( void ) {
1331 V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1337 static int host_dev_deinit(void) {
1342 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1343 struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1346 ERROR("palacios: failed to do guest_init for host device\n");
1351 INIT_LIST_HEAD(&(host_dev->devs));
1352 palacios_spinlock_init(&(host_dev->lock));
1354 *vm_data = host_dev;
1357 add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1363 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1365 struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1366 remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT);
1367 palacios_spinlock_deinit(&(host_dev->lock));
1368 palacios_free(host_dev);
1375 static struct linux_ext host_dev_ext = {
1376 .name = "HOST_DEVICE_INTERFACE",
1377 .init = host_dev_init,
1378 .deinit = host_dev_deinit,
1379 .guest_init = host_dev_guest_init,
1380 .guest_deinit = host_dev_guest_deinit
1384 register_extension(&host_dev_ext);