Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Merge branch 'devel' of ssh://palacios@newskysaw/home/palacios/palacios into devel
Jack Lange [Wed, 8 Jun 2011 17:55:47 +0000 (12:55 -0500)]
Conflicts:

linux_module/palacios-vm.c

linux_module/palacios-graphics-console.c
linux_module/palacios-host-dev.c
linux_module/palacios-vm.c
linux_module/palacios.h
linux_usr/v3_os_debug.c
linux_usr/v3_user_host_dev.c
palacios/src/devices/Kconfig
palacios/src/devices/lnx_virtio_nic.c
palacios/src/vnet/vnet_core.c

index 3cd70c9..21c9457 100644 (file)
@@ -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++;
index c20e0fa..29cb303 100644 (file)
 #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_datalen<sizeof(struct palacios_host_dev_host_request_response)) { 
+               // bad user
                spin_unlock_irqrestore(&(dev->lock),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;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) { 
        spin_lock_irqsave(&(dev->lock),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;
index a434f17..d19e705 100644 (file)
@@ -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;
     }
index 8923361..62f43f1 100644 (file)
@@ -66,7 +66,7 @@ struct v3_guest {
 
 
     struct rb_root vm_ctrls;
-
+    struct list_head exts;
 
     struct list_head files;
     struct list_head streams;
index c530964..af55b8a 100644 (file)
@@ -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;
index 709db76..6996bfa 100644 (file)
@@ -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) { 
index d49bb9e..d3a41f1 100644 (file)
@@ -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       
index 3c519aa..7a4eb4a 100644 (file)
@@ -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;
 
index 8cf2364..3a1ad38 100644 (file)
@@ -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;