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 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 // safe to unlock here since if we are in the waiting state
478 // the palacios side will not modify the request
479 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
481 if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) {
482 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
483 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
484 return -EFAULT; // failed to copy!
488 DEEP_DEBUG_PRINT("palacios: hostdev: have request\n");
490 return 1; // have request for you
496 case V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL: {
500 palacios_spinlock_lock_irqsave(&(dev->lock),f);
502 DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n");
504 if (!(dev->waiting) || !(dev->req)) {
505 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
506 DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n");
507 return 0; // no request available now
510 // Safe to unlock here since if we are in the waiting
511 // state, the request will not be modified by the palacios side
512 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
514 if (copy_to_user(argp,dev->req,dev->req->data_len)) {
515 ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url);
516 return -EFAULT; // failed to copy!
519 DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n");
521 return 1; // copied request for you
525 case V3_HOST_DEV_USER_RESPONSE_PUSH_IOCTL: {
528 uint64_t user_datalen;
531 palacios_spinlock_lock_irqsave(&(dev->lock),f);
533 DEEP_DEBUG_PRINT("palacios: hostdev: push response\n");
535 if (!(dev->waiting)) {
536 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
537 ERROR("palacios: hostdev: no matching request for pushed response\n");
538 return 0; // no request outstanding, so we do not need a response!
541 // Safe to unlock here as the palacios side will not
542 // modify the request or copy the response until we
543 // reset dev->waiting
544 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
546 if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) {
547 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
548 return -EFAULT; // failed to copy!
551 if (user_datalen<sizeof(struct palacios_host_dev_host_request_response)) {
553 ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url);
557 if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) {
559 DEEP_DEBUG_PRINT("palacios: response not big enough, resizing on device \"%s\"\n",dev->url);
562 if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) {
563 ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url);
568 //We only copy data_len bytes from user, but we will
569 //overwrite the len field, so we preserve and then restore
570 old_len = dev->resp->len;
571 if (copy_from_user(dev->resp, argp, user_datalen)) {
572 dev->resp->len=old_len;
573 ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url);
574 return -EFAULT; // failed to copy!
576 dev->resp->len=old_len;
578 DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n");
579 // now have valid response!
582 // wake the palacios side up so that it sees it
583 cycle_response_request(dev);
590 ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url);
597 static struct file_operations host_dev_fops = {
598 .poll = host_dev_poll,
599 .release = host_dev_release,
600 .compat_ioctl = host_dev_ioctl,
601 .unlocked_ioctl = host_dev_ioctl,
606 static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data)
608 void __user * argp = (void __user *)arg;
610 struct palacios_host_dev * host_dev = priv_data;
611 struct palacios_host_device_user *dev;
612 unsigned long f1, f2;
617 if (copy_from_user(url, argp, MAX_URL)) {
618 ERROR("copy from user error getting url for host device connect...\n");
622 // currently only support user: types:
623 if (strncasecmp(url,"user:",5)) {
624 ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
628 INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url);
630 // We will scan the list looking for the relevant
631 // URL. If we don't find it after a while, we give up
633 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
634 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
635 list_for_each_entry(dev,&(host_dev->devs), node) {
636 if (!strncasecmp(url,dev->url,MAX_URL)) {
638 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
639 if (dev->connected) {
640 ERROR("palacios: device for \"%s\" is already connected!\n",url);
641 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
642 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
645 dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
647 ERROR("palacios: cannot create fd for device \"%s\"\n",url);
648 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
649 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
655 palacios_free(dev->req);
659 palacios_free(dev->resp);
662 INFO("palacios: connected fd for device \"%s\"\n",url);
663 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
664 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
667 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
670 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
672 ssleep(RENDEZVOUS_RETRY_SECS);
675 ERROR("palacios: timeout waiting for connection for device \"%s\"",url);
688 /***************************************************************************************
690 Following this is the implementation of the palacios->host interface
692 **************************************************************************************/
695 /* Attempt to rendezvous with the user device if no device is currently connected */
696 static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
701 if (dev->connected) {
706 INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
708 // Now wait until we are noticed!
709 for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
710 palacios_spinlock_lock_irqsave(&(dev->lock),f);
711 if (dev->connected) {
712 INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
713 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
716 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
717 ssleep(RENDEZVOUS_RETRY_SECS);
720 ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
722 // We stay in the list because a future rendezvous might happen
728 /* Creates the device without rendezvous */
729 static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
732 v3_guest_dev_intr_t gintr,
733 void *host_priv_data)
735 struct v3_guest *guest= (struct v3_guest*)host_priv_data;
736 struct palacios_host_device_user *dev;
737 struct palacios_host_dev * host_dev = NULL;
741 I will create the device in the list and then wait
742 for the user side to attach
750 host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
752 if (host_dev == NULL) {
753 ERROR("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
758 if (strncasecmp(url,"user:",5)) {
759 ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
763 // Check to see if a device of this url already exists, which would be ugly
764 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
765 list_for_each_entry(dev,&(host_dev->devs), node) {
766 if (!strncasecmp(url,dev->url,MAX_URL)) {
768 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
769 ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
773 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
776 INFO("palacios: creating host device \"%s\"\n",url);
778 dev = palacios_alloc(sizeof(struct palacios_host_device_user));
781 ERROR("palacios: cannot allocate for host device \"%s\"\n",url);
785 memset(dev,0,sizeof(struct palacios_host_device_user));
787 strncpy(dev->url,url,MAX_URL);
789 dev->guestdev = gdev;
791 dev->guestintr = gintr;
795 palacios_spinlock_init(&(dev->lock));
797 init_waitqueue_head(&(dev->user_wait_queue));
798 init_waitqueue_head(&(dev->host_wait_queue));
800 // Insert ourselves into the list
801 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
802 list_add(&(dev->node),&(host_dev->devs));
803 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
805 INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
813 static int palacios_host_dev_close(v3_host_dev_t hostdev)
815 unsigned long f1, f2;
817 struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
818 struct palacios_host_dev * host_dev = NULL;
820 INFO("palacios: closing host device \"%s\"\n",dev->url);
822 if ((dev == NULL) || (dev->guest == NULL)) {
826 host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
829 if (host_dev == NULL) {
833 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
835 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
837 if (dev->connected) {
839 // After this, any user side request will return -EFAULT
842 list_del(&(dev->node));
844 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
845 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
847 palacios_spinlock_deinit(&(dev->lock));
849 palacios_host_dev_user_free(dev);
857 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
862 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
866 DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
868 if (palacios_host_dev_rendezvous(dev)) {
869 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
872 palacios_spinlock_lock_irqsave(&(dev->lock),f);
875 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
876 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 // if we're not waiting on user, we have access to
881 // to the request and response fields
882 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
884 // resize request (no data)
885 if (!palacios_bigenough_reqresp(dev->req,0)) {
887 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
889 if (palacios_resize_reqresp(&(dev->req),0,0)) {
890 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
896 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
898 dev->req->op_len=len;
900 dev->req->conf_addr=0;
901 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
905 // hand over to the user space and wait for it to respond
906 cycle_request_response(dev);
908 // We're back! So now we'll hand the response back to Palacios
909 // no need to lock, we own the response since
912 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
914 memcpy(dest,dev->resp->data, op_len);
919 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
924 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
928 DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa);
931 if (palacios_host_dev_rendezvous(dev)) {
932 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
933 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
936 palacios_spinlock_lock_irqsave(&(dev->lock),f);
939 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
940 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);
944 // We now are assured to have ownership over request
945 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
947 // resize request (no data)
948 if (!palacios_bigenough_reqresp(dev->req,0)) {
950 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
952 if (palacios_resize_reqresp(&(dev->req),0,0)) {
953 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
958 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
960 dev->req->op_len=len;
962 dev->req->conf_addr=0;
963 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
967 // hand over to the user space and wait for it to respond
968 cycle_request_response(dev);
970 // We're back! So now we'll hand the response back to Palacios
972 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
974 memcpy(dest,dev->resp->data, op_len);
979 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
984 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
988 DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p (len=%lld)\n",(void*)offset, len);
991 if (palacios_host_dev_rendezvous(dev)) {
992 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
993 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
996 palacios_spinlock_lock_irqsave(&(dev->lock),f);
999 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1000 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);
1004 // Now have exclusive access to request
1005 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1007 // resize request (no data)
1008 if (!palacios_bigenough_reqresp(dev->req,0)) {
1010 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1012 if (palacios_resize_reqresp(&(dev->req),0,0)) {
1013 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1018 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1020 dev->req->op_len=len;
1022 dev->req->conf_addr=offset;
1023 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1027 // hand over to the user space and wait for it to respond
1028 cycle_request_response(dev);
1030 // We're back! So now we'll hand the response back to Palacios
1032 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1034 memcpy(dest,dev->resp->data, op_len);
1040 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1045 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1049 DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1052 if (palacios_host_dev_rendezvous(dev)) {
1053 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1054 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1057 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1060 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1061 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);
1065 // have exclusive access to request
1066 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1069 if (!palacios_bigenough_reqresp(dev->req,len)) {
1071 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1073 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1074 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1079 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1080 dev->req->port=port;
1081 dev->req->op_len=len;
1083 dev->req->conf_addr=0;
1084 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1086 memcpy(dev->req->data,src,len);
1090 // hand over to the user space and wait for it to respond
1091 cycle_request_response(dev);
1093 // We're back! So now we'll hand the response back to Palacios
1095 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1101 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1106 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1110 DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1113 if (palacios_host_dev_rendezvous(dev)) {
1114 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1115 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1119 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1122 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1123 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);
1127 // Now have exclusive access to request
1128 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1131 if (!palacios_bigenough_reqresp(dev->req,len)) {
1133 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1135 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1136 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1141 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1143 dev->req->op_len=len;
1145 dev->req->conf_addr=0;
1146 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1148 memcpy(dev->req->data,src,len);
1152 // hand over to the user space and wait for it to respond
1153 cycle_request_response(dev);
1155 // We're back! So now we'll hand the response back to Palacios
1157 op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1165 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1170 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1174 DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1177 if (palacios_host_dev_rendezvous(dev)) {
1178 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1179 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1182 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1185 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1186 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);
1190 // Have exclusive access to request
1191 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1194 if (!palacios_bigenough_reqresp(dev->req,len)) {
1196 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1198 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1199 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1204 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1206 dev->req->op_len=len;
1208 dev->req->conf_addr=offset;
1209 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1211 memcpy(dev->req->data,src,len);
1215 // hand over to the user space and wait for it to respond
1216 cycle_request_response(dev);
1218 // We're back! So now we'll hand the response back to Palacios
1220 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1226 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1236 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1237 .open = palacios_host_dev_open_deferred,
1238 .close = palacios_host_dev_close,
1239 .read_io = palacios_host_dev_read_io,
1240 .write_io = palacios_host_dev_write_io,
1241 .read_mem = palacios_host_dev_read_mem,
1242 .write_mem = palacios_host_dev_write_mem,
1243 .read_config = palacios_host_dev_read_conf,
1244 .write_config = palacios_host_dev_write_conf,
1245 .ack_irq = palacios_host_dev_ack_irq,
1250 static int host_dev_init( void ) {
1251 V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1257 static int host_dev_deinit(void) {
1262 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1263 struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1266 ERROR("palacios: failed to do guest_init for host device\n");
1271 INIT_LIST_HEAD(&(host_dev->devs));
1272 palacios_spinlock_init(&(host_dev->lock));
1274 *vm_data = host_dev;
1277 add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1283 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1285 struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1286 remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT);
1287 palacios_spinlock_deinit(&(host_dev->lock));
1288 palacios_free(host_dev);
1295 static struct linux_ext host_dev_ext = {
1296 .name = "HOST_DEVICE_INTERFACE",
1297 .init = host_dev_init,
1298 .deinit = host_dev_deinit,
1299 .guest_init = host_dev_guest_init,
1300 .guest_deinit = host_dev_guest_deinit
1304 register_extension(&host_dev_ext);