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);
788 dev->url[MAX_URL-1] = 0;
790 dev->guestdev = gdev;
792 dev->guestintr = gintr;
796 palacios_spinlock_init(&(dev->lock));
798 init_waitqueue_head(&(dev->user_wait_queue));
799 init_waitqueue_head(&(dev->host_wait_queue));
801 // Insert ourselves into the list
802 palacios_spinlock_lock_irqsave(&(host_dev->lock),f);
803 list_add(&(dev->node),&(host_dev->devs));
804 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f);
806 INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
814 static int palacios_host_dev_close(v3_host_dev_t hostdev)
816 unsigned long f1, f2;
818 struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
819 struct palacios_host_dev * host_dev = NULL;
821 INFO("palacios: closing host device \"%s\"\n",dev->url);
823 if ((dev == NULL) || (dev->guest == NULL)) {
827 host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
830 if (host_dev == NULL) {
834 palacios_spinlock_lock_irqsave(&(host_dev->lock),f1);
836 palacios_spinlock_lock_irqsave(&(dev->lock),f2);
838 if (dev->connected) {
840 // After this, any user side request will return -EFAULT
843 list_del(&(dev->node));
845 palacios_spinlock_unlock_irqrestore(&(dev->lock),f2);
846 palacios_spinlock_unlock_irqrestore(&(host_dev->lock),f1);
848 palacios_spinlock_deinit(&(dev->lock));
850 palacios_host_dev_user_free(dev);
858 static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev,
863 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
867 DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port);
869 if (palacios_host_dev_rendezvous(dev)) {
870 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
873 palacios_spinlock_lock_irqsave(&(dev->lock),f);
876 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
877 ERROR("palacios: guest issued i/o read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
881 // if we're not waiting on user, we have access to
882 // to the request and response fields
883 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
885 // resize request (no data)
886 if (!palacios_bigenough_reqresp(dev->req,0)) {
888 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
890 if (palacios_resize_reqresp(&(dev->req),0,0)) {
891 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
897 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO;
899 dev->req->op_len=len;
901 dev->req->conf_addr=0;
902 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
906 // hand over to the user space and wait for it to respond
907 cycle_request_response(dev);
909 // We're back! So now we'll hand the response back to Palacios
910 // no need to lock, we own the response since
913 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
915 memcpy(dest,dev->resp->data, op_len);
920 static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev,
925 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
929 DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa);
932 if (palacios_host_dev_rendezvous(dev)) {
933 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
934 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
937 palacios_spinlock_lock_irqsave(&(dev->lock),f);
940 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
941 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);
945 // We now are assured to have ownership over request
946 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
948 // resize request (no data)
949 if (!palacios_bigenough_reqresp(dev->req,0)) {
951 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
953 if (palacios_resize_reqresp(&(dev->req),0,0)) {
954 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
959 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM;
961 dev->req->op_len=len;
963 dev->req->conf_addr=0;
964 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
968 // hand over to the user space and wait for it to respond
969 cycle_request_response(dev);
971 // We're back! So now we'll hand the response back to Palacios
973 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
975 memcpy(dest,dev->resp->data, op_len);
980 static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev,
985 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
989 DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p (len=%lld)\n",(void*)offset, len);
992 if (palacios_host_dev_rendezvous(dev)) {
993 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
994 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
997 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1000 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1001 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);
1005 // Now have exclusive access to request
1006 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1008 // resize request (no data)
1009 if (!palacios_bigenough_reqresp(dev->req,0)) {
1011 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1013 if (palacios_resize_reqresp(&(dev->req),0,0)) {
1014 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1019 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF;
1021 dev->req->op_len=len;
1023 dev->req->conf_addr=offset;
1024 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response);
1028 // hand over to the user space and wait for it to respond
1029 cycle_request_response(dev);
1031 // We're back! So now we'll hand the response back to Palacios
1033 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1035 memcpy(dest,dev->resp->data, op_len);
1041 static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev,
1046 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1050 DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port);
1053 if (palacios_host_dev_rendezvous(dev)) {
1054 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1055 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1058 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1061 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1062 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);
1066 // have exclusive access to request
1067 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1070 if (!palacios_bigenough_reqresp(dev->req,len)) {
1072 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1074 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1075 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1080 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO;
1081 dev->req->port=port;
1082 dev->req->op_len=len;
1084 dev->req->conf_addr=0;
1085 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1087 memcpy(dev->req->data,src,len);
1091 // hand over to the user space and wait for it to respond
1092 cycle_request_response(dev);
1094 // We're back! So now we'll hand the response back to Palacios
1096 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1102 static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev,
1107 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1111 DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa);
1114 if (palacios_host_dev_rendezvous(dev)) {
1115 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1116 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1120 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1123 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1124 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);
1128 // Now have exclusive access to request
1129 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1132 if (!palacios_bigenough_reqresp(dev->req,len)) {
1134 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1136 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1137 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1142 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM;
1144 dev->req->op_len=len;
1146 dev->req->conf_addr=0;
1147 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1149 memcpy(dev->req->data,src,len);
1153 // hand over to the user space and wait for it to respond
1154 cycle_request_response(dev);
1156 // We're back! So now we'll hand the response back to Palacios
1158 op_len= dev->resp->op_len < len ? dev->resp->op_len : len ;
1166 static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev,
1171 struct palacios_host_device_user *dev = (struct palacios_host_device_user *)hostdev;
1175 DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset);
1178 if (palacios_host_dev_rendezvous(dev)) {
1179 //palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1180 ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
1183 palacios_spinlock_lock_irqsave(&(dev->lock),f);
1186 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1187 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);
1191 // Have exclusive access to request
1192 palacios_spinlock_unlock_irqrestore(&(dev->lock),f);
1195 if (!palacios_bigenough_reqresp(dev->req,len)) {
1197 DEEP_DEBUG_PRINT("palacios: request not big enough, resizing on device \"%s\"\n",dev->url);
1199 if (palacios_resize_reqresp(&(dev->req),len,0)) {
1200 ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url);
1205 dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF;
1207 dev->req->op_len=len;
1209 dev->req->conf_addr=offset;
1210 dev->req->data_len=sizeof(struct palacios_host_dev_host_request_response)+len;
1212 memcpy(dev->req->data,src,len);
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 op_len = dev->resp->op_len < len ? dev->resp->op_len : len ;
1227 static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq)
1237 static struct v3_host_dev_hooks palacios_host_dev_hooks = {
1238 .open = palacios_host_dev_open_deferred,
1239 .close = palacios_host_dev_close,
1240 .read_io = palacios_host_dev_read_io,
1241 .write_io = palacios_host_dev_write_io,
1242 .read_mem = palacios_host_dev_read_mem,
1243 .write_mem = palacios_host_dev_write_mem,
1244 .read_config = palacios_host_dev_read_conf,
1245 .write_config = palacios_host_dev_write_conf,
1246 .ack_irq = palacios_host_dev_ack_irq,
1251 static int host_dev_init( void ) {
1252 V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
1258 static int host_dev_deinit(void) {
1263 static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
1264 struct palacios_host_dev * host_dev = palacios_alloc(sizeof(struct palacios_host_dev));
1267 ERROR("palacios: failed to do guest_init for host device\n");
1272 INIT_LIST_HEAD(&(host_dev->devs));
1273 palacios_spinlock_init(&(host_dev->lock));
1275 *vm_data = host_dev;
1278 add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
1284 static int host_dev_guest_deinit(struct v3_guest * guest, void * vm_data) {
1286 struct palacios_host_dev * host_dev = (struct palacios_host_dev *) vm_data;
1287 remove_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT);
1288 palacios_spinlock_deinit(&(host_dev->lock));
1289 palacios_free(host_dev);
1296 static struct linux_ext host_dev_ext = {
1297 .name = "HOST_DEVICE_INTERFACE",
1298 .init = host_dev_init,
1299 .deinit = host_dev_deinit,
1300 .guest_init = host_dev_guest_init,
1301 .guest_deinit = host_dev_guest_deinit
1305 register_extension(&host_dev_ext);