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...)
135 #if SHALLOW_DEBUG == 1
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 // possible overflow here, but only if user is asking for too much...
373 void *temp = palacios_alloc(op.len);
375 DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n");
378 ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url);
382 if (v3_host_dev_read_guest_mem(dev,
387 ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url);
392 if (copy_to_user(op.data,temp,op.len)) {
393 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
405 case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: {
408 DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n");
410 temp = palacios_alloc(op.len);
413 ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url);
417 if (copy_from_user(temp,op.data,op.len)) {
418 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
423 if (v3_host_dev_write_guest_mem(dev,
428 ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url);
439 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_RAISE_GUEST: {
441 DEEP_DEBUG_PRINT("palacios: hostdev: irq raise guest\n");
443 return v3_host_dev_raise_irq(dev, dev->guestdev, dev->guestintr, op.irq);
446 case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_LOWER_GUEST: {
448 DEEP_DEBUG_PRINT("palacios: hostdev: irq lower guest\n");
450 return v3_host_dev_lower_irq(dev, dev->guestdev, dev->guestintr, op.irq);
455 ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url);
462 case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: {
467 DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n");
469 palacios_spinlock_lock_irqsave(&(dev->lock),f);
471 if (!(dev->waiting)) {
472 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
473 DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n");
474 schedule(); // avoid livelock for polling user space process SUSPICOUS
475 return 0; // no request available now
478 // safe to unlock here since if we are in the waiting state
479 // the palacios side will not modify the request
480 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
482 if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) {
483 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
484 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
485 return -EFAULT; // failed to copy!
489 DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
491 return 1; // have request for you
497 case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
501 palacios_spinlock_lock_irqsave(&(dev->lock),f);
503 DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
505 if (!(dev->waiting) || !(dev->req)) {
506 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
507 DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
508 return 0; // no request available now
511 // Safe to unlock here since if we are in the waiting
512 // state, the request will not be modified by the palacios side
513 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
515 if (copy_to_user(argp,dev->req,dev->req->data_len)) {
516 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
517 return -EFAULT; // failed to copy!
520 DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
522 return 1; // copied request for you
526 case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
529 uint64_t user_datalen;
532 palacios_spinlock_lock_irqsave(&(dev->lock),f);
534 DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
536 if (!(dev->waiting)) {
537 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
538 ERROR("palacios: hostdev: no matching request for pushed response\n");
539 return 0; // no request outstanding, so we do not need a response!
542 // Safe to unlock here as the palacios side will not
543 // modify the request or copy the response until we
544 // reset dev->waiting
545 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
547 if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) {
548 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
549 return -EFAULT; // failed to copy!
552 if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) {
554 ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
558 if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
560 DEEP_DEBUG_PRINT("palacios: response not big enough, resizing on device \"%s\"\n",dev->url);
563 if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
564 ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
569 //We only copy data_len bytes from user, but we will
570 //overwrite the len field, so we preserve and then restore
571 old_len = dev->resp->len;
572 if (copy_from_user(dev->resp, argp, user_datalen)) {
573 dev->resp->len=old_len;
574 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
575 return -EFAULT; // failed to copy!
577 dev->resp->len=old_len;
579 DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
580 // now have valid response!
583 // wake the palacios side up so that it sees it
584 cycle_response_request(dev);
591 ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
598 static struct file_operations host_dev_fops = {
599 .poll = host_dev_poll,
600 .release = host_dev_release,
601 .compat_ioctl = host_dev_ioctl,
602 .unlocked_ioctl = host_dev_ioctl,
607 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data)
609 void __user * argp = (void __user *)arg;
611 struct palacios_host_dev * host_dev = priv_data;
612 struct palacios_host_device_user *dev;
613 unsigned long f1, f2;
618 if (copy_from_user(url, argp, MAX_URL)) {
619 ERROR("copy from user error getting url for host device connect...\n");
623 // currently only support user: types:
624 if (strncasecmp(url,"user:",5)) {
625 ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
629 INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
631 // We will scan the list looking for the relevant
632 // URL. If we don't find it after a while, we give up
634 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
635 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
636 list_for_each_entry(dev,&(host_dev->devs), node) {
637 if (!strncasecmp(url,dev->url,MAX_URL)) {
639 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
640 if (dev->connected) {
641 ERROR("palacios: device for \"%s\" is already connected!\n",url);
642 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
643 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
646 dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
648 ERROR("palacios: cannot create fd for device \"%s\"\n",url);
649 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
650 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
656 palacios_free(dev->req);
660 palacios_free(dev->resp);
663 INFO("palacios: connected fd for device \"%s\"\n",url);
664 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
665 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
668 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
671 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
673 ssleep(RENDEZVOUS_RETRY_SECS);
676 ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
689 /***************************************************************************************
691 Following this is the implementation of the palacios->host interface
693 **************************************************************************************/
696 /* Attempt to rendezvous with the user device if no device is currently connected */
697 static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
702 if (dev->connected) {
707 INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
709 // Now wait until we are noticed!
710 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
711 palacios_spinlock_lock_irqsave(&(dev->lock),f);
712 if (dev->connected) {
713 INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
714 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
717 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
718 ssleep(RENDEZVOUS_RETRY_SECS);
721 ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
723 // We stay in the list because a future rendezvous might happen
729 /* Creates the device without rendezvous */
730 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
733 v3_guest_dev_intr_t gintr,
734 void *host_priv_data)
736 struct v3_guest *guest= (struct v3_guest*)host_priv_data;
737 struct palacios_host_device_user *dev;
738 struct palacios_host_dev * host_dev = NULL;
742 I will create the device in the list and then wait
743 for the user side to attach
751 host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
753 if (host_dev == NULL) {
754 ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
759 if (strncasecmp(url,"user:",5)) {
760 ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
764 // Check to see if a device of this url already exists, which would be ugly
765 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
766 list_for_each_entry(dev,&(host_dev->devs), node) {
767 if (!strncasecmp(url,dev->url,MAX_URL)) {
769 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
770 ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
774 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
777 INFO("palacios: creating host device \"%s\"\n",url);
779 dev = palacios_alloc(sizeof(struct palacios_host_device_user));
782 ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
786 memset(dev,0,sizeof(struct palacios_host_device_user));
788 strncpy(dev->url,url,MAX_URL);
789 dev->url[MAX_URL-1] = 0;
791 dev->guestdev = gdev;
793 dev->guestintr = gintr;
797 palacios_spinlock_init(&(dev->lock));
799 init_waitqueue_head(&(dev->user_wait_queue));
800 init_waitqueue_head(&(dev->host_wait_queue));
802 // Insert ourselves into the list
803 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
804 list_add(&(dev->node),&(host_dev->devs));
805 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
807 INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
815 static int palacios_host_dev_close(v3_host_dev_t hostdev)
817 unsigned long f1, f2;
819 struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
820 struct palacios_host_dev * host_dev = NULL;
822 INFO("palacios: closing host device \"%s\"\n",dev->url);
824 if ((dev == NULL) || (dev->guest == NULL)) {
828 host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
831 if (host_dev == NULL) {
835 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
837 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
839 if (dev->connected) {
841 // After this, any user side request will return -EFAULT
844 list_del(&(dev->node));
846 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
847 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
849 palacios_spinlock_deinit(&(dev->lock));
851 palacios_host_dev_user_free(dev);
859 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
864 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
868 DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
870 if (palacios_host_dev_rendezvous(dev)) {
871 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
874 palacios_spinlock_lock_irqsave(&(dev->lock),f);
877 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
878 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);
882 // if we're not waiting on user, we have access to
883 // to the request and response fields
884 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
886 // resize request (no data)
887 if (!palacios_bigenough_reqresp(dev->req,0)) {
889 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
891 if (palacios_resize_reqresp(&(dev->req),0,0)) {
892 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
898 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
900 dev->req->op_len=len;
902 dev->req->conf_addr=0;
903 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
907 // hand over to the user space and wait for it to respond
908 cycle_request_response(dev);
910 // We're back! So now we'll hand the response back to Palacios
911 // no need to lock, we own the response since
914 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
916 memcpy(dest,dev->resp->data, op_len);
921 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
926 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
930 DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa);
933 if (palacios_host_dev_rendezvous(dev)) {
934 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
935 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
938 palacios_spinlock_lock_irqsave(&(dev->lock),f);
941 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
942 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);
946 // We now are assured to have ownership over request
947 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
949 // resize request (no data)
950 if (!palacios_bigenough_reqresp(dev->req,0)) {
952 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
954 if (palacios_resize_reqresp(&(dev->req),0,0)) {
955 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
960 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
962 dev->req->op_len=len;
964 dev->req->conf_addr=0;
965 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
969 // hand over to the user space and wait for it to respond
970 cycle_request_response(dev);
972 // We're back! So now we'll hand the response back to Palacios
974 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
976 memcpy(dest,dev->resp->data, op_len);
981 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
986 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
990 DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p (len=%lld)\n",(void*)offset, len);
993 if (palacios_host_dev_rendezvous(dev)) {
994 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
995 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
998 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1001 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1002 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);
1006 // Now have exclusive access to request
1007 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1009 // resize request (no data)
1010 if (!palacios_bigenough_reqresp(dev->req,0)) {
1012 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1014 if (palacios_resize_reqresp(&(dev->req),0,0)) {
1015 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1020 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1022 dev->req->op_len=len;
1024 dev->req->conf_addr=offset;
1025 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1029 // hand over to the user space and wait for it to respond
1030 cycle_request_response(dev);
1032 // We're back! So now we'll hand the response back to Palacios
1034 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1036 memcpy(dest,dev->resp->data, op_len);
1042 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1047 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1051 DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1054 if (palacios_host_dev_rendezvous(dev)) {
1055 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1056 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1059 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1062 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1063 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);
1067 // have exclusive access to request
1068 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1071 if (!palacios_bigenough_reqresp(dev->req,len)) {
1073 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1075 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1076 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1081 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1082 dev->req->port=port;
1083 dev->req->op_len=len;
1085 dev->req->conf_addr=0;
1086 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1088 memcpy(dev->req->data,src,len);
1092 // hand over to the user space and wait for it to respond
1093 cycle_request_response(dev);
1095 // We're back! So now we'll hand the response back to Palacios
1097 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1103 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1108 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1112 DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1115 if (palacios_host_dev_rendezvous(dev)) {
1116 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1117 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1121 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1124 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1125 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);
1129 // Now have exclusive access to request
1130 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1133 if (!palacios_bigenough_reqresp(dev->req,len)) {
1135 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1137 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1138 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1143 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1145 dev->req->op_len=len;
1147 dev->req->conf_addr=0;
1148 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1150 memcpy(dev->req->data,src,len);
1154 // hand over to the user space and wait for it to respond
1155 cycle_request_response(dev);
1157 // We're back! So now we'll hand the response back to Palacios
1159 op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1167 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1172 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1176 DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1179 if (palacios_host_dev_rendezvous(dev)) {
1180 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1181 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1184 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1187 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1188 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);
1192 // Have exclusive access to request
1193 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1196 if (!palacios_bigenough_reqresp(dev->req,len)) {
1198 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1200 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1201 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1206 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1208 dev->req->op_len=len;
1210 dev->req->conf_addr=offset;
1211 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1213 memcpy(dev->req->data,src,len);
1217 // hand over to the user space and wait for it to respond
1218 cycle_request_response(dev);
1220 // We're back! So now we'll hand the response back to Palacios
1222 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1228 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1238 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1239 .open = palacios_host_dev_open_deferred,
1240 .close = palacios_host_dev_close,
1241 .read_io = palacios_host_dev_read_io,
1242 .write_io = palacios_host_dev_write_io,
1243 .read_mem = palacios_host_dev_read_mem,
1244 .write_mem = palacios_host_dev_write_mem,
1245 .read_config = palacios_host_dev_read_conf,
1246 .write_config = palacios_host_dev_write_conf,
1247 .ack_irq = palacios_host_dev_ack_irq,
1252 static int host_dev_init( void ) {
1253 V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1259 static int host_dev_deinit(void) {
1264 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1265 struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1268 ERROR("palacios: failed to do guest_init for host device\n");
1273 INIT_LIST_HEAD(&(host_dev->devs));
1274 palacios_spinlock_init(&(host_dev->lock));
1276 *vm_data = host_dev;
1279 add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1285 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1287 struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1288 remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT);
1289 palacios_spinlock_deinit(&(host_dev->lock));
1290 palacios_free(host_dev);
1297 static struct linux_ext host_dev_ext = {
1298 .name = "HOST_DEVICE_INTERFACE",
1299 .init = host_dev_init,
1300 .deinit = host_dev_deinit,
1301 .guest_init = host_dev_guest_init,
1302 .guest_deinit = host_dev_guest_deinit
1306 register_extension(&host_dev_ext);