From: Jack Lange Date: Wed, 8 Jun 2011 17:55:47 +0000 (-0500) Subject: Merge branch 'devel' of ssh://palacios@newskysaw/home/palacios/palacios into devel X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?a=commitdiff_plain;h=5e16adcc49f8c77319004ada0276ccd301c67dd1;hp=fed3449f4fd2fab7f27a17e0970e954bd2d69abc;p=palacios-OLD.git Merge branch 'devel' of ssh://palacios@newskysaw/home/palacios/palacios into devel Conflicts: linux_module/palacios-vm.c --- diff --git a/linux_module/palacios-graphics-console.c b/linux_module/palacios-graphics-console.c index 3cd70c9..21c9457 100644 --- a/linux_module/palacios-graphics-console.c +++ b/linux_module/palacios-graphics-console.c @@ -150,10 +150,11 @@ static void g_release_data_rw(v3_graphics_console_t cons) static int g_changed(v3_graphics_console_t cons) { + +#if 0 struct palacios_graphics_console *gc = (struct palacios_graphics_console *) cons; -#if 0 int rc = !(gc->num_updates % 1000); gc->num_updates++; diff --git a/linux_module/palacios-host-dev.c b/linux_module/palacios-host-dev.c index c20e0fa..29cb303 100644 --- a/linux_module/palacios-host-dev.c +++ b/linux_module/palacios-host-dev.c @@ -112,6 +112,24 @@ #define RENDEZVOUS_WAIT_SECS 60 #define RENDEZVOUS_RETRY_SECS 1 +#define DEEP_DEBUG 0 +#define SHALLOW_DEBUG 0 + +#if DEEP_DEBUG +#define DEEP_DEBUG_PRINT(fmt, args...) printk((fmt), ##args) +#else +#define DEEP_DEBUG_PRINT(fmt, args...) +#endif + +#if SHALLOW_DEBUG +#define SHALLOW_DEBUG_PRINT(fmt, args...) printk((fmt), ##args) +#else +#define SHALLOW_DEBUG_PRINT(fmt, args...) +#endif + + +#define ERROR(fmt, args...) printk((fmt), ##args) +#define INFO(fmt, args...) printk((fmt), ##args) struct palacios_host_device_user { spinlock_t lock; @@ -152,15 +170,49 @@ static void palacios_host_dev_user_free(struct palacios_host_device_user *dev) kfree(dev); } + +// +// Is this structure big enough for the data_size we will use? +// +// THIS FUNCTION CAN BE CALLED WHILE INTERRUPTS ARE OFF +// +static int palacios_bigenough_reqresp(struct palacios_host_dev_host_request_response *r, uint64_t data_size) +{ + if (!r) { + return 0; + } else { + if (((r->len)-sizeof(struct palacios_host_dev_host_request_response)) < data_size) { + return 0; + } else { + return 1; + } + } +} + +// +// Resize a request/response structure so that it will fit data_size bytes +// +// At the end of this, *r->len >= sizeof(struct)+data_size +// +// THIS FUNCTION MAY SLEEP AS IT CALLS KMALLOC +// DO NOT CALL IT WHILE HOLDING A SPIN LOCK WITH INTERRUPTS OFF +// static int palacios_resize_reqresp(struct palacios_host_dev_host_request_response **r, uint64_t data_size, int copy) { - if (!*r) { + + DEEP_DEBUG_PRINT("palacios: hostdev: resize 0x%p to %llu\n",*r,data_size); + + if ((*r)==0) { // allocate it + DEEP_DEBUG_PRINT("palacios: hostdev: attempt alloc\n"); *r = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL); - if (!*r) { + DEEP_DEBUG_PRINT("palacios: hostdev: kmalloc done\n"); + if ((*r)==0) { + ERROR("palacios: hostdev: failed to allocate\n"); return -1; } else { (*r)->len=sizeof(struct palacios_host_dev_host_request_response)+data_size; + DEEP_DEBUG_PRINT("palacios: hostdev: allocated\n"); return 0; } } else { @@ -169,6 +221,7 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons if (data_size<=cur_len) { // do nothing + DEEP_DEBUG_PRINT("palacios: hostdev: size ok\n"); return 0; } else { struct palacios_host_dev_host_request_response *new; @@ -179,6 +232,7 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons } new = kmalloc(sizeof(struct palacios_host_dev_host_request_response)+data_size,GFP_KERNEL); if (!new) { + ERROR("palacios: hostdev: failed to reallocate\n"); return -1; } else { new->len=sizeof(struct palacios_host_dev_host_request_response)+data_size; @@ -188,6 +242,7 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons kfree(*r); } *r=new; + DEEP_DEBUG_PRINT("palacios: hostdev: reallocated\n"); return 0; } } @@ -196,16 +251,21 @@ static int palacios_resize_reqresp(struct palacios_host_dev_host_request_respons static void cycle_request_response(struct palacios_host_device_user *dev) { + DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response\n"); // wake up user side so that polls fall through wake_up_interruptible(&(dev->user_wait_queue)); // put us to sleep until the user side wakes us up - wait_event_interruptible((dev->host_wait_queue), (dev->waiting==0)); + while (wait_event_interruptible((dev->host_wait_queue), (dev->waiting==0)) != 0) {} + + DEEP_DEBUG_PRINT("palacios: hostdev: cycle request to response - done\n"); } static void cycle_response_request(struct palacios_host_device_user *dev) { + DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request\n"); // wake up host side wake_up_interruptible(&(dev->host_wait_queue)); + DEEP_DEBUG_PRINT("palacios: hostdev: cycle response to request - done\n"); } @@ -224,7 +284,10 @@ static unsigned int host_dev_poll(struct file * filp, struct palacios_host_device_user * dev = filp->private_data; unsigned long f; + SHALLOW_DEBUG_PRINT("palacios: hostdev: poll\n"); + if (!dev->connected) { + ERROR("palcios: hostdev: poll on unconnected device\n"); return -EFAULT; } @@ -233,6 +296,7 @@ static unsigned int host_dev_poll(struct file * filp, if (dev->waiting) { // Yes, we have a request if you want it! spin_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: hostdev: poll done immediate\n"); return POLLIN | POLLRDNORM; } @@ -243,6 +307,7 @@ static unsigned int host_dev_poll(struct file * filp, spin_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: hostdev: poll delayed\n"); // We will get called again when that queue is woken up return 0; @@ -254,7 +319,7 @@ static int host_dev_release(struct inode * i, struct file * filp) struct palacios_host_device_user *dev = filp->private_data; unsigned long f; - printk("palacios: user side is closing host device \"%s\"\n",dev->url); + INFO("palacios: user side is closing host device \"%s\"\n",dev->url); spin_lock_irqsave(&(dev->lock), f); dev->connected = 0; @@ -273,8 +338,11 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u struct palacios_host_device_user *dev = fp->private_data; + DEEP_DEBUG_PRINT("palacios: hostdev: ioctl %u\n",val); + if (!dev->connected) { + ERROR("palacios: hostdev: ioctl on unconnected device\n"); return -EFAULT; } @@ -284,16 +352,20 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u struct palacios_host_dev_user_op op; if (copy_from_user(&op,argp,sizeof(struct palacios_host_dev_user_op))) { - printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url); return -EFAULT; } + + DEEP_DEBUG_PRINT("palacios: hostdev: user request push, type %d\n",op.type); switch (op.type) { case PALACIOS_HOST_DEV_USER_REQUEST_READ_GUEST: { void *temp = kmalloc(op.len,GFP_KERNEL); + DEEP_DEBUG_PRINT("palacios: hostdev: read guest\n"); + if (!temp) { - printk("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to allocate enough for read guest request for host device \"%s\"\n",dev->url); return -EFAULT; } @@ -302,13 +374,13 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u op.gpa, temp, op.len) != op.len) { - printk("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to read enough from guest for host device \"%s\"\n",dev->url); kfree(temp); return -EFAULT; } if (copy_to_user(op.data,temp,op.len)) { - printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url); kfree(temp); return -EFAULT; } @@ -321,16 +393,19 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u case PALACIOS_HOST_DEV_USER_REQUEST_WRITE_GUEST: { + void *temp; + + DEEP_DEBUG_PRINT("palacios: hostdev: write guest\n"); - void *temp = kmalloc(op.len,GFP_KERNEL); + temp = kmalloc(op.len,GFP_KERNEL); if (!temp) { - printk("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to allocate enough for write guest request for host device \"%s\"\n",dev->url); return -EFAULT; } if (copy_from_user(temp,op.data,op.len)) { - printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url); kfree(temp); return -EFAULT; } @@ -340,7 +415,7 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u op.gpa, temp, op.len) != op.len) { - printk("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url); + ERROR("palacios: unable to write enough to guest for host device \"%s\"\n",dev->url); kfree(temp); return -EFAULT; } @@ -353,12 +428,14 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u case PALACIOS_HOST_DEV_USER_REQUEST_IRQ_GUEST: { + DEEP_DEBUG_PRINT("palacios: hostdev: irq guest\n"); + return v3_host_dev_raise_irq(dev->guestdev, dev, op.irq); } break; default: - printk("palacios: unknown user request to host device \"%s\"\n",dev->url); + ERROR("palacios: unknown user request to host device \"%s\"\n",dev->url); return -EFAULT; break; } @@ -368,22 +445,30 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u case V3_HOST_DEV_HOST_REQUEST_SIZE_IOCTL: { unsigned long f; + + + DEEP_DEBUG_PRINT("palacios: hostdev: request size of request\n"); spin_lock_irqsave(&(dev->lock),f); if (!(dev->waiting)) { spin_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: hostdev: no request available\n"); + schedule(); // avoid livelock for polling user space process SUSPICOUS return 0; // no request available now } if (copy_to_user(argp,&(dev->req->data_len),sizeof(uint64_t))) { - printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! + } spin_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: hostdev: have request\n"); + return 1; // have request for you } @@ -396,18 +481,24 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u spin_lock_irqsave(&(dev->lock),f); - if (!(dev->waiting)) { + DEEP_DEBUG_PRINT("palacios: hostdev: pull request\n"); + + if (!(dev->waiting) || !(dev->req)) { spin_unlock_irqrestore(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: hostdev: no request to pull\n"); return 0; // no request available now } + if (copy_to_user(argp,dev->req,dev->req->data_len)) { - printk("palacios: unable to copy to user for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: unable to copy to user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! } - + spin_unlock_irqrestore(&(dev->lock),f); + + DEEP_DEBUG_PRINT("palacios: hostdev: request pulled\n"); return 1; // copied request for you } @@ -417,46 +508,77 @@ static int host_dev_ioctl(struct inode *ip, struct file *fp, unsigned int val, u unsigned long f; uint64_t user_datalen; + uint64_t old_len; spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: hostdev: push response\n"); + if (!(dev->waiting)) { spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: hostdev: no matching request for pushed response\n"); return 0; // no request outstanding, so we do not need a response! } if (copy_from_user(&user_datalen,argp,sizeof(uint64_t))) { - printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! } - - if (palacios_resize_reqresp(&(dev->resp),user_datalen,0)) { - printk("palacios: unable to resize to accept request of size %llu from user for host device \"%s\"\n",user_datalen,dev->url); + + if (user_datalenlock),f); + ERROR("palacios: user has response that is too small on host device \"%s\"\n",dev->url); return -EFAULT; - } - + } + + if (!palacios_bigenough_reqresp(dev->resp,user_datalen-sizeof(struct palacios_host_dev_host_request_response))) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: response not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->resp),user_datalen-sizeof(struct palacios_host_dev_host_request_response),0)) { + ERROR("palacios: unable to resize to accept response of size %llu from user for host device \"%s\"\n",user_datalen,dev->url); + return -EFAULT; + } else { + // reacquire the lock + // There shouldn't be a race here, since there should + // be exactly one user space thread giving us a response for this device + // and it is blocked waiting for us to finish + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacuired lock on device \"%s\"\n",dev->url); + } + } + + //We only copy data_len bytes from user, but we will + //overwrite the len field, so we preserve and then restore + old_len = dev->resp->len; if (copy_from_user(dev->resp, argp, user_datalen)) { - printk("palacios: unable to copy from user for host device \"%s\"\n",dev->url); + dev->resp->len=old_len; spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: unable to copy from user for host device \"%s\"\n",dev->url); return -EFAULT; // failed to copy! } + dev->resp->len=old_len; + DEEP_DEBUG_PRINT("palacios: hostdev: valid response pushed\n"); // now have valid response! dev->waiting=0; + spin_unlock_irqrestore(&(dev->lock),f); + // wake the palacios side up so that it sees it cycle_response_request(dev); - spin_unlock_irqrestore(&(dev->lock),f); - return 1; // done } break; default: - printk("palacios: unknown ioctl for host device \"%s\"\n",dev->url); + ERROR("palacios: unknown ioctl for host device \"%s\"\n",dev->url); return -EFAULT; break; } @@ -483,11 +605,11 @@ int connect_host_dev(struct v3_guest * guest, char *url) // currently only support user: types: if (strncasecmp(url,"user:",5)) { - printk("palacios: do not currently support host devices of type in \"%s\"\n",url); + ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url); return -1; } - printk("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url); + INFO("palacios: attempting to rendezvous with palacios side of host device \"%s\"\n",url); // We will scan the list looking for the relevant // URL. If we don't find it after a while, we give up @@ -499,14 +621,14 @@ int connect_host_dev(struct v3_guest * guest, char *url) // found it spin_lock_irqsave(&(dev->lock),f2); if (dev->connected) { - printk("palacios: device for \"%s\" is already connected!\n",url); + ERROR("palacios: device for \"%s\" is already connected!\n",url); spin_unlock_irqrestore(&(dev->lock),f2); spin_unlock_irqrestore(&(guest->hostdev.lock),f1); return -1; } else { dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0); if (dev->fd<0) { - printk("palacios: cannot create fd for device \"%s\"\n",url); + ERROR("palacios: cannot create fd for device \"%s\"\n",url); spin_unlock_irqrestore(&(dev->lock),f2); spin_unlock_irqrestore(&(guest->hostdev.lock),f1); return -1; @@ -521,7 +643,7 @@ int connect_host_dev(struct v3_guest * guest, char *url) kfree(dev->resp); dev->resp=0; } - printk("palacios: connected fd for device \"%s\"\n",url); + INFO("palacios: connected fd for device \"%s\"\n",url); spin_unlock_irqrestore(&(dev->lock),f2); spin_unlock_irqrestore(&(guest->hostdev.lock),f1); return dev->fd; @@ -534,7 +656,7 @@ int connect_host_dev(struct v3_guest * guest, char *url) ssleep(RENDEZVOUS_RETRY_SECS); } - printk("palacios: timeout waiting for connection for device \"%s\"",url); + ERROR("palacios: timeout waiting for connection for device \"%s\"",url); return -1; @@ -570,7 +692,7 @@ static v3_host_dev_t palacios_host_dev_open(char *url, if (strncasecmp(url,"user:",5)) { - printk("palacios: do not currently support devices of type in \"%s\"\n",url); + ERROR("palacios: do not currently support devices of type in \"%s\"\n",url); return NULL; } @@ -580,19 +702,19 @@ static v3_host_dev_t palacios_host_dev_open(char *url, if (!strncasecmp(url,dev->url,MAX_URL)) { // found it spin_unlock_irqrestore(&(guest->hostdev.lock),f1); - printk("palacios: a host device with url \"%s\" already exists in the guest!\n",url); + ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url); return NULL; } } spin_unlock_irqrestore(&(guest->hostdev.lock),f1); - printk("palacios: creating host device \"%s\"\n",url); + INFO("palacios: creating host device \"%s\"\n",url); dev = kmalloc(sizeof(struct palacios_host_device_user),GFP_KERNEL); if (!dev) { - printk("palacios: cannot allocate for host device \"%s\"\n",url); + ERROR("palacios: cannot allocate for host device \"%s\"\n",url); return NULL; } @@ -609,7 +731,7 @@ static v3_host_dev_t palacios_host_dev_open(char *url, init_waitqueue_head(&(dev->user_wait_queue)); init_waitqueue_head(&(dev->host_wait_queue)); - printk("palacios: attempting to rendezvous with user side of host device \"%s\"\n",url); + INFO("palacios: attempting to rendezvous with user side of host device \"%s\"\n",url); // Insert ourselves into the list spin_lock_irqsave(&(guest->hostdev.lock),f1); @@ -621,7 +743,7 @@ static v3_host_dev_t palacios_host_dev_open(char *url, for (i=0;ilock),f2); if (dev->connected){ - printk("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd); + INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd); spin_unlock_irqrestore(&(dev->lock),f2); return dev; } @@ -629,7 +751,7 @@ static v3_host_dev_t palacios_host_dev_open(char *url, ssleep(RENDEZVOUS_RETRY_SECS); } - printk("palacios: timeout waiting for user side to connect to host device \"%s\"",url); + ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",url); // get us out of the list spin_lock_irqsave(&(guest->hostdev.lock),f1); @@ -647,7 +769,7 @@ static int palacios_host_dev_close(v3_host_dev_t hostdev) struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev; - printk("palacios: closing host device \"%s\"\n",dev->url); + INFO("palacios: closing host device \"%s\"\n",dev->url); spin_lock_irqsave(&(dev->guest->hostdev.lock),f1); @@ -680,22 +802,44 @@ static uint64_t palacios_host_dev_read_io(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; + DEEP_DEBUG_PRINT("palacios: hostdev: read io port 0x%x\n",port); + + spin_lock_irqsave(&(dev->lock),f); if (dev->waiting) { - printk("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); spin_unlock_irqrestore(&(dev->lock),f); + 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); return 0; } if (!dev->connected) { - printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); return 0; } - // resize request and response in case they will need it - palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data + + // resize request (no data) + if (!palacios_bigenough_reqresp(dev->req,0)) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->req),0,0)) { + ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); + return 0; + } else { + // reacquire the lock + // There shouldn't be a race here since there should not be another + // request from palacios until this one finishes + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); + } + } + dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_IO; dev->req->port=port; @@ -733,21 +877,40 @@ static uint64_t palacios_host_dev_read_mem(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; + DEEP_DEBUG_PRINT("palacios: hostdev: read mem 0x%p\n",gpa); + spin_lock_irqsave(&(dev->lock),f); if (dev->waiting) { - printk("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected); spin_unlock_irqrestore(&(dev->lock),f); + 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); return 0; } if (!dev->connected) { - printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); return 0; } - // resize request and response in case they will need it - palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data + // resize request (no data) + if (!palacios_bigenough_reqresp(dev->req,0)) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->req),0,0)) { + ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); + return 0; + } else { + // reacquire the lock + // There shouldn't be a race here since there should not be another + // request from palacios until this one finishes + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); + } + } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_MEM; dev->req->port=0; @@ -785,21 +948,40 @@ static uint64_t palacios_host_dev_read_conf(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; + DEEP_DEBUG_PRINT("palacios: hostdev: read conf 0x%p\n",(void*)offset); + spin_lock_irqsave(&(dev->lock),f); if (dev->waiting) { - printk("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected); spin_unlock_irqrestore(&(dev->lock),f); + 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); return 0; } if (!dev->connected) { - printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); return 0; } - // resize request and response in case they will need it - palacios_resize_reqresp(&(dev->req),0,0); // request doesn't carry data + // resize request (no data) + if (!palacios_bigenough_reqresp(dev->req,0)) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->req),0,0)) { + ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); + return 0; + } else { + // reacquire the lock + // There shouldn't be a race here since there should not be another + // request from palacios until this one finishes + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); + } + } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_READ_CONF; dev->req->port=0; @@ -838,21 +1020,40 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; + DEEP_DEBUG_PRINT("palacios: hostdev: write io port 0x%x \n",port); + spin_lock_irqsave(&(dev->lock),f); if (dev->waiting) { - printk("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); spin_unlock_irqrestore(&(dev->lock),f); + 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); return 0; } if (!dev->connected) { - printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); return 0; } - // resize request and response in case they will need it - palacios_resize_reqresp(&(dev->req),len,0); // make room for data + // resize request + if (!palacios_bigenough_reqresp(dev->req,len)) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->req),len,0)) { + ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); + return 0; + } else { + // reacquire the lock + // There shouldn't be a race here since there should not be another + // request from palacios until this one finishes + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); + } + } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_IO; dev->req->port=port; @@ -864,9 +1065,9 @@ static uint64_t palacios_host_dev_write_io(v3_host_dev_t hostdev, memcpy(dev->req->data,src,len); dev->waiting=1; - - spin_unlock_irqrestore(&(dev->lock),f); + spin_unlock_irqrestore(&(dev->lock),f); + // hand over to the user space and wait for it to respond cycle_request_response(dev); @@ -891,21 +1092,40 @@ static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; + DEEP_DEBUG_PRINT("palacios: hostdev: write mem 0x%p\n",gpa); + spin_lock_irqsave(&(dev->lock),f); if (dev->waiting) { - printk("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected); spin_unlock_irqrestore(&(dev->lock),f); + 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); return 0; } if (!dev->connected) { - printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); return 0; } - // resize request and response in case they will need it - palacios_resize_reqresp(&(dev->req),len,0); // make room for data + // resize request + if (!palacios_bigenough_reqresp(dev->req,len)) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->req),len,0)) { + ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); + return 0; + } else { + // reacquire the lock + // There shouldn't be a race here since there should not be another + // request from palacios until this one finishes + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); + } + } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_MEM; dev->req->port=0; @@ -935,12 +1155,6 @@ static uint64_t palacios_host_dev_write_mem(v3_host_dev_t hostdev, } -static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq) -{ - // we don't care - return 0; -} - static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev, @@ -952,21 +1166,40 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev, unsigned long f; uint64_t op_len; + DEEP_DEBUG_PRINT("palacios: hostdev: write conf 0x%p\n",(void*)offset); + spin_lock_irqsave(&(dev->lock),f); if (dev->waiting) { - printk("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected); spin_unlock_irqrestore(&(dev->lock),f); + 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); return 0; } if (!dev->connected) { - printk("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); spin_unlock_irqrestore(&(dev->lock),f); + ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url); return 0; } - // resize request and response in case they will need it - palacios_resize_reqresp(&(dev->req),len,0); // make room for data + // resize request + if (!palacios_bigenough_reqresp(dev->req,len)) { + // not enough room. + // we drop the lock, turn on interrupts, resize, and then retry + DEEP_DEBUG_PRINT("palacios: request not big enough, dropping lock to resize on device \"%s\"\n",dev->url); + + spin_unlock_irqrestore(&(dev->lock),f); + + if (palacios_resize_reqresp(&(dev->req),len,0)) { + ERROR("palacios: cannot resize for request on device \"%s\"\n",dev->url); + return 0; + } else { + // reacquire the lock + // There shouldn't be a race here since there should not be another + // request from palacios until this one finishes + spin_lock_irqsave(&(dev->lock),f); + DEEP_DEBUG_PRINT("palacios: reacquired lock on device \"%s\"\n",dev->url); + } + } dev->req->type=PALACIOS_HOST_DEV_HOST_REQUEST_WRITE_CONF; dev->req->port=0; @@ -993,9 +1226,15 @@ static uint64_t palacios_host_dev_write_conf(v3_host_dev_t hostdev, spin_unlock_irqrestore(&(dev->lock),f); return op_len; - } +} +static int palacios_host_dev_ack_irq(v3_host_dev_t hostdev, uint8_t irq) +{ + // we don't care + return 0; +} + @@ -1014,7 +1253,8 @@ static struct v3_host_dev_hooks palacios_host_dev_hooks = { -int palacios_init_host_dev( void ) { +int palacios_init_host_dev( void ) +{ V3_Init_Host_Device_Support(&palacios_host_dev_hooks); return 0; diff --git a/linux_module/palacios-vm.c b/linux_module/palacios-vm.c index a434f17..d19e705 100644 --- a/linux_module/palacios-vm.c +++ b/linux_module/palacios-vm.c @@ -129,6 +129,7 @@ static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) { #ifdef V3_CONFIG_HOST_DEVICE #include "palacios-host-dev.h" +#define HOST_DEV_URL_LEN 256 #endif extern struct class * v3_class; @@ -178,7 +179,10 @@ static long v3_vm_ioctl(struct file * filp, } case V3_VM_HOST_DEV_CONNECT: { -#ifdef V3_CONFIG_HOST_DEV +#ifdef V3_CONFIG_HOST_DEVICE + void __user * argp = (void __user *)arg; + char host_dev_url[HOST_DEV_URL_LEN]; + if (copy_from_user(host_dev_url, argp, HOST_DEV_URL_LEN)) { printk("copy from user error getting url for host device connect...\n"); return -EFAULT; @@ -256,7 +260,6 @@ static struct file_operations v3_vm_fops = { }; -extern int vm_running; extern u32 pg_allocs; extern u32 pg_frees; extern u32 mallocs; @@ -298,7 +301,6 @@ int start_palacios_vm(void * arg) { if (err) { printk("Fails to add cdev\n"); - v3_free_vm(guest->v3_ctx); complete(&(guest->start_done)); return -1; } @@ -306,7 +308,15 @@ int start_palacios_vm(void * arg) { if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){ printk("Fails to create device\n"); cdev_del(&(guest->cdev)); - v3_free_vm(guest->v3_ctx); + complete(&(guest->start_done)); + return -1; + } + + guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name); + + if (guest->v3_ctx == NULL) { + printk("palacios: failed to create vm\n"); + cdev_del(&(guest->cdev)); complete(&(guest->start_done)); return -1; } diff --git a/linux_module/palacios.h b/linux_module/palacios.h index 8923361..62f43f1 100644 --- a/linux_module/palacios.h +++ b/linux_module/palacios.h @@ -66,7 +66,7 @@ struct v3_guest { struct rb_root vm_ctrls; - + struct list_head exts; struct list_head files; struct list_head streams; diff --git a/linux_usr/v3_os_debug.c b/linux_usr/v3_os_debug.c index c530964..af55b8a 100644 --- a/linux_usr/v3_os_debug.c +++ b/linux_usr/v3_os_debug.c @@ -29,6 +29,10 @@ int do_work(struct palacios_host_dev_host_request_response *req, putchar(req->data[i]); } *resp = malloc(sizeof(struct palacios_host_dev_host_request_response)); + if (!*resp) { + printf("Cannot allocate response\n"); + return -1; + } **resp=*req; (*resp)->len = (*resp)->data_len = sizeof(struct palacios_host_dev_host_request_response); (*resp)->op_len = numchars; diff --git a/linux_usr/v3_user_host_dev.c b/linux_usr/v3_user_host_dev.c index 709db76..6996bfa 100644 --- a/linux_usr/v3_user_host_dev.c +++ b/linux_usr/v3_user_host_dev.c @@ -55,7 +55,11 @@ int v3_user_host_dev_pull_request(int devfd, struct palacios_host_dev_host_reque return -1; } else { struct palacios_host_dev_host_request_response *r = malloc(len); - + + if (!r) { + return -1; + } + rc=ioctl(devfd, V3_HOST_DEV_HOST_REQUEST_PULL_IOCTL,r); if (rc<=0) { diff --git a/palacios/src/devices/Kconfig b/palacios/src/devices/Kconfig index d49bb9e..d3a41f1 100644 --- a/palacios/src/devices/Kconfig +++ b/palacios/src/devices/Kconfig @@ -156,7 +156,7 @@ config DEBUG_VIRTIO_SYM config LINUX_VIRTIO_NET bool "Enable Virtio Network Device" default n - depends on PCI + depends on PCI && VNET help Enable the Virtio Net @@ -366,7 +366,7 @@ config RAMDISK Includes the RAM based disk backend config DEBUG_RAMDISK - bool "RAMDISK baskend debugging" + bool "RAMDISK backend debugging" depends on RAMDISK && DEBUG_ON help Enable debugging for the ram based disk backend diff --git a/palacios/src/devices/lnx_virtio_nic.c b/palacios/src/devices/lnx_virtio_nic.c index 3c519aa..7a4eb4a 100644 --- a/palacios/src/devices/lnx_virtio_nic.c +++ b/palacios/src/devices/lnx_virtio_nic.c @@ -174,7 +174,7 @@ static int virtio_init_state(struct virtio_net_state * virtio) virtio->virtio_cfg.pci_isr = 0; - virtio->mergeable_rx_bufs = 0; + virtio->mergeable_rx_bufs = 1; virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC); if(virtio->mergeable_rx_bufs) { @@ -219,12 +219,13 @@ static int tx_one_pkt(struct guest_info * core, } +/*copy data into ring buffer */ static inline int copy_data_to_desc(struct guest_info * core, - struct virtio_net_state * virtio_state, - struct vring_desc * desc, - uchar_t * buf, - uint_t buf_len, - uint_t dst_offset){ + struct virtio_net_state * virtio_state, + struct vring_desc * desc, + uchar_t * buf, + uint_t buf_len, + uint_t dst_offset){ uint32_t len; uint8_t * desc_buf = NULL; @@ -232,8 +233,8 @@ static inline int copy_data_to_desc(struct guest_info * core, PrintDebug("Could not translate buffer address\n"); return -1; } - len = (desc->length < buf_len)?(desc->length - dst_offset):buf_len; - memcpy(desc_buf+dst_offset, buf, len); + len = (desc->length < (buf_len+dst_offset))?(desc->length - dst_offset):buf_len; + memcpy(desc_buf + dst_offset, buf, len); return len; } @@ -282,7 +283,7 @@ static int handle_pkt_tx(struct guest_info * core, uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; int desc_cnt = get_desc_count(q, desc_idx); - if(desc_cnt > 2){ + if(desc_cnt != 2){ PrintError("VNIC: merged rx buffer not supported, desc_cnt %d\n", desc_cnt); goto exit_error; } @@ -305,7 +306,7 @@ static int handle_pkt_tx(struct guest_info * core, goto exit_error; } if(buf_desc->next & VIRTIO_NEXT_FLAG){ - V3_Net_Print(2, "Virtio NIC: TX more buffer need to read\n"); + PrintError("Virtio NIC: TX more buffer need to read\n"); } q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size]; @@ -320,9 +321,9 @@ static int handle_pkt_tx(struct guest_info * core, v3_unlock_irqrestore(virtio_state->tx_lock, flags); if (txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { - v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev); + v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, + 0, virtio_state->pci_dev); virtio_state->virtio_cfg.pci_isr = 0x1; - virtio_state->stats.rx_interrupts ++; } @@ -386,8 +387,9 @@ static int virtio_io_write(struct guest_info *core, struct virtio_net_state * virtio = (struct virtio_net_state *)private_data; int port_idx = port % virtio->io_range_size; - PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", private_data, - port, port_idx, length, *(uint32_t *)src); + PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", + private_data, port, port_idx, + length, *(uint32_t *)src); switch (port_idx) { case GUEST_FEATURES_PORT: @@ -408,17 +410,23 @@ static int virtio_io_write(struct guest_info *core, uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector; switch (queue_idx) { case 0: - virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr); + virtio_setup_queue(core, virtio, + &virtio->rx_vq, + pfn, page_addr); break; case 1: - virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr); + virtio_setup_queue(core, virtio, + &virtio->tx_vq, + pfn, page_addr); if(virtio->tx_notify == 0){ disable_cb(&virtio->tx_vq); vnet_thread_wakeup(virtio->poll_thread); } break; case 2: - virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr); + virtio_setup_queue(core, virtio, + &virtio->ctrl_vq, + pfn, page_addr); break; default: break; @@ -481,8 +489,8 @@ static int virtio_io_read(struct guest_info *core, int port_idx = port % virtio->io_range_size; uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector; - PrintDebug("Virtio NIC %p: Read for port 0x%x (index =%d), length=%d\n", private_data, - port, port_idx, length); + PrintDebug("Virtio NIC %p: Read for port 0x%x (index =%d), length=%d\n", + private_data, port, port_idx, length); switch (port_idx) { case HOST_FEATURES_PORT: @@ -544,7 +552,8 @@ static int virtio_io_read(struct guest_info *core, case VIRTIO_ISR_PORT: *(uint8_t *)dst = virtio->virtio_cfg.pci_isr; virtio->virtio_cfg.pci_isr = 0; - v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev); + v3_pci_lower_irq(virtio->virtio_dev->pci_bus, + 0, virtio->pci_dev); break; case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN: @@ -552,7 +561,8 @@ static int virtio_io_read(struct guest_info *core, break; default: - PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx); + PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", + port_idx); return -1; } @@ -565,136 +575,155 @@ static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) { struct virtio_net_state * virtio = (struct virtio_net_state *)private_data; struct virtio_queue * q = &(virtio->rx_vq); struct virtio_net_hdr_mrg_rxbuf hdr; - uint32_t data_len; unsigned long flags; + uint8_t kick_guest = 0; V3_Net_Print(2, "Virtio-NIC: virtio_rx: size: %d\n", size); - if(net_debug >= 4){ - v3_hexdump(buf, size, NULL, 0); - } - - flags = v3_lock_irqsave(virtio->rx_lock); - - data_len = size; - memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf)); - if (q->ring_avail_addr == 0) { + if (!q->ring_avail_addr) { V3_Net_Print(2, "Virtio NIC: RX Queue not set\n"); virtio->stats.rx_dropped ++; - goto err_exit; + + return -1; } + memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf)); + + flags = v3_lock_irqsave(virtio->rx_lock); + if (q->cur_avail_idx != q->avail->index){ - addr_t hdr_addr = 0; - uint16_t buf_idx = 0; - uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; - struct vring_desc * hdr_desc = NULL; - struct vring_desc * buf_desc = NULL; - uint32_t hdr_len = 0; - uint32_t len; - - hdr_desc = &(q->desc[hdr_idx]); - if (v3_gpa_to_hva(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) { - V3_Net_Print(2, "Virtio NIC: Could not translate receive buffer address\n"); - virtio->stats.rx_dropped ++; - goto err_exit; - } + uint16_t buf_idx; + struct vring_desc * buf_desc; + uint32_t hdr_len, len; + uint32_t offset = 0; - hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); + hdr_len = (virtio->mergeable_rx_bufs)? + sizeof(struct virtio_net_hdr_mrg_rxbuf): + sizeof(struct virtio_net_hdr); if(virtio->mergeable_rx_bufs){/* merged buffer */ - uint32_t offset = 0; - len = 0; - hdr.num_buffers = 0; + struct vring_desc * hdr_desc; + uint16_t old_idx = q->cur_avail_idx; + buf_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; hdr_desc = &(q->desc[buf_idx]); - hdr_desc->flags &= ~VIRTIO_NEXT_FLAG; - len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, hdr_desc, buf, data_len, hdr_len); + len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), + virtio, hdr_desc, buf, size, hdr_len); + if(len < 0){ + goto err_exit; + } offset += len; - hdr.num_buffers ++; q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size]; - q->used->ring[q->used->index % q->queue_size].length = hdr_len + len; + q->used->ring[q->used->index % q->queue_size].length = hdr_len + offset; q->cur_avail_idx ++; + hdr.num_buffers ++; - while(offset < data_len) { + while(offset < size) { buf_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; buf_desc = &(q->desc[buf_idx]); - len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf + offset, data_len - offset, 0); - if (len <= 0){ - V3_Net_Print(2, "Virtio NIC:merged buffer, %d buffer size %d\n", hdr.num_buffers, data_len); - virtio->stats.rx_dropped ++; + len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), + virtio, buf_desc, buf+offset, size-offset, 0); + if (len < 0){ + V3_Net_Print(2, "Virtio NIC:merged buffer, %d buffer size %d\n", + hdr.num_buffers, len); + q->cur_avail_idx = old_idx; goto err_exit; } offset += len; buf_desc->flags &= ~VIRTIO_NEXT_FLAG; - hdr.num_buffers ++; q->used->ring[(q->used->index + hdr.num_buffers) % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size]; q->used->ring[(q->used->index + hdr.num_buffers) % q->queue_size].length = len; q->cur_avail_idx ++; + + hdr.num_buffers ++; } + + copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), + virtio, hdr_desc, (uchar_t *)&hdr, hdr_len, 0); q->used->index += hdr.num_buffers; - copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, hdr_desc, (uchar_t *)&hdr, hdr_len, 0); }else{ - hdr_desc = &(q->desc[buf_idx]); - copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, hdr_desc, (uchar_t *)&hdr, hdr_len, 0); - - buf_idx = hdr_desc->next; + buf_idx = q->avail->ring[q->cur_avail_idx % q->queue_size]; buf_desc = &(q->desc[buf_idx]); - len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf, data_len, 0); - if (len < data_len) { - V3_Net_Print(2, "Virtio NIC: ring buffer len less than pkt size, merged buffer not supported, buffer size %d\n", len); - virtio->stats.rx_dropped ++; - - goto err_exit; + + /* copy header */ + len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), + virtio, buf_desc, (uchar_t *)&(hdr.hdr), hdr_len, 0); + if(len < hdr_len){ + V3_Net_Print(2, "Virtio NIC: rx copy header error %d, hdr_len %d\n", + len, hdr_len); + goto err_exit; + } + + len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), + virtio, buf_desc, buf, size, hdr_len); + if(len < 0){ + V3_Net_Print(2, "Virtio NIC: rx copy data error %d\n", len); + goto err_exit; + } + offset += len; + + /* copy rest of data */ + while(offset < size && + (buf_desc->flags & VIRTIO_NEXT_FLAG)){ + buf_desc = &(q->desc[buf_desc->next]); + len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), + virtio, buf_desc, buf+offset, size-offset, 0); + if (len < 0) { + break; + } + offset += len; } buf_desc->flags &= ~VIRTIO_NEXT_FLAG; + + if(offset < size){ + V3_Net_Print(2, "Virtio NIC: rx not enough ring buffer, buffer size %d\n", + len); + goto err_exit; + } q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size]; - q->used->ring[q->used->index % q->queue_size].length = data_len + hdr_len; /* This should be the total length of data sent to guest (header+pkt_data) */ - q->used->index++; - q->cur_avail_idx++; + q->used->ring[q->used->index % q->queue_size].length = size + hdr_len; /* This should be the total length of data sent to guest (header+pkt_data) */ + q->used->index ++; + q->cur_avail_idx ++; } virtio->stats.rx_pkts ++; virtio->stats.rx_bytes += size; } else { V3_Net_Print(2, "Virtio NIC: Guest RX queue is full\n"); - virtio->stats.rx_dropped ++; + virtio->stats.rx_dropped ++; - /* kick guest to refill the queue */ - virtio->virtio_cfg.pci_isr = 0x1; - v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev); - v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].pcpu_id, 0); - virtio->stats.rx_interrupts ++; - - goto err_exit; + /* kick guest to refill RX queue */ + kick_guest = 1; } - if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) { - V3_Net_Print(2, "Raising IRQ %d\n", virtio->pci_dev->config_header.intr_line); + v3_unlock_irqrestore(virtio->rx_lock, flags); + + if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG) || kick_guest) { + V3_Net_Print(2, "Virtio NIC: RX Raising IRQ %d\n", + virtio->pci_dev->config_header.intr_line); virtio->virtio_cfg.pci_isr = 0x1; v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev); - virtio->stats.rx_interrupts ++; } - v3_unlock_irqrestore(virtio->rx_lock, flags); - /* notify guest if it is in guest mode */ - if(virtio->rx_notify == 1 && + if((kick_guest || virtio->rx_notify == 1) && V3_Get_CPU() != virtio->virtio_dev->vm->cores[0].pcpu_id){ - v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].pcpu_id, 0); + v3_interrupt_cpu(virtio->virtio_dev->vm, + virtio->virtio_dev->vm->cores[0].pcpu_id, + 0); } return 0; err_exit: - + virtio->stats.rx_dropped ++; v3_unlock_irqrestore(virtio->rx_lock, flags); return -1; @@ -726,7 +755,8 @@ static struct v3_device_ops dev_ops = { static int virtio_tx_flush(void * args){ struct virtio_net_state *virtio = (struct virtio_net_state *)args; - V3_Print("Virtio TX Poll Thread Starting for %s\n", virtio->vm->name); + V3_Print("Virtio TX Poll Thread Starting for %s\n", + virtio->vm->name); while(1){ if(virtio->tx_notify == 0){ @@ -749,7 +779,7 @@ static int register_dev(struct virtio_dev_state * virtio, int tmp_ports = num_ports; int i; - // This gets the number of ports, rounded up to a power of 2 + /* This gets the number of ports, rounded up to a power of 2 */ net_state->io_range_size = 1; // must be a power of 2 while (tmp_ports > 0) { tmp_ports >>= 1; @@ -757,8 +787,8 @@ static int register_dev(struct virtio_dev_state * virtio, } /* this is to account for any low order bits being set in num_ports - * if there are none, then num_ports was already a power of 2 so we shift right to reset it - */ + * if there are none, then num_ports was already a power of 2 so we shift right to reset it + */ if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) { net_state->io_range_size >>= 1; } @@ -767,7 +797,8 @@ static int register_dev(struct virtio_dev_state * virtio, bars[i].type = PCI_BAR_NONE; } - PrintDebug("Virtio-NIC io_range_size = %d\n", net_state->io_range_size); + PrintDebug("Virtio-NIC io_range_size = %d\n", + net_state->io_range_size); bars[0].type = PCI_BAR_IO; bars[0].default_base_port = -1; @@ -901,7 +932,8 @@ static int connect_fn(struct v3_vm_info * info, net_state->tx_notify = 0; net_state->rx_notify = 0; - net_state->timer = v3_add_timer(&(info->cores[0]),&timer_ops,net_state); + net_state->timer = v3_add_timer(&(info->cores[0]), + &timer_ops,net_state); PrintError("net_state 0x%p\n", (void *)net_state); @@ -909,7 +941,8 @@ static int connect_fn(struct v3_vm_info * info, ops->frontend_data = net_state; memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN); - net_state->poll_thread = vnet_start_thread(virtio_tx_flush, (void *)net_state, "Virtio_Poll"); + net_state->poll_thread = vnet_start_thread(virtio_tx_flush, + (void *)net_state, "Virtio_Poll"); net_state->status = 1; diff --git a/palacios/src/vnet/vnet_core.c b/palacios/src/vnet/vnet_core.c index 8cf2364..3a1ad38 100644 --- a/palacios/src/vnet/vnet_core.c +++ b/palacios/src/vnet/vnet_core.c @@ -99,7 +99,9 @@ struct vnet_queue { static struct { struct list_head routes; struct list_head devs; - + + uint8_t status; + uint32_t num_routes; uint32_t route_idx; uint32_t num_devs;