]> err.no Git - linux-2.6/blobdiff - drivers/lguest/lguest_user.c
lguest: per-vcpu lguest timers
[linux-2.6] / drivers / lguest / lguest_user.c
index ee405b38383d8c4c89eb3560bd3fab2c2ecfade9..f231b9be0b643bc0784d7976cb3980b7974f961b 100644 (file)
@@ -8,20 +8,22 @@
 #include <linux/fs.h>
 #include "lg.h"
 
-/*L:315 To force the Guest to stop running and return to the Launcher, the
- * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest.  The
- * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
+/*L:055 When something happens, the Waker process needs a way to stop the
+ * kernel running the Guest and return to the Launcher.  So the Waker writes
+ * LHREQ_BREAK and the value "1" to /dev/lguest to do this.  Once the Launcher
+ * has done whatever needs attention, it writes LHREQ_BREAK and "0" to release
+ * the Waker. */
 static int break_guest_out(struct lguest *lg, const unsigned long __user *input)
 {
        unsigned long on;
 
-       /* Fetch whether they're turning break on or off.. */
+       /* Fetch whether they're turning break on or off. */
        if (get_user(on, input) != 0)
                return -EFAULT;
 
        if (on) {
                lg->break_out = 1;
-               /* Pop it out (may be running on different CPU) */
+               /* Pop it out of the Guest (may be running on different CPU) */
                wake_up_process(lg->tsk);
                /* Wait for them to reset it */
                return wait_event_interruptible(lg->break_wq, !lg->break_out);
@@ -53,12 +55,20 @@ static int user_send_irq(struct lguest *lg, const unsigned long __user *input)
 static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
 {
        struct lguest *lg = file->private_data;
+       struct lg_cpu *cpu;
+       unsigned int cpu_id = *o;
 
        /* You must write LHREQ_INITIALIZE first! */
        if (!lg)
                return -EINVAL;
 
-       /* If you're not the task which owns the guest, go away. */
+       /* Watch out for arbitrary vcpu indexes! */
+       if (cpu_id >= lg->nr_cpus)
+               return -EINVAL;
+
+       cpu = &lg->cpus[cpu_id];
+
+       /* If you're not the task which owns the Guest, go away. */
        if (current != lg->tsk)
                return -EPERM;
 
@@ -83,7 +93,20 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
                lg->pending_notify = 0;
 
        /* Run the Guest until something interesting happens. */
-       return run_guest(lg, (unsigned long __user *)user);
+       return run_guest(cpu, (unsigned long __user *)user);
+}
+
+static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
+{
+       if (id >= NR_CPUS)
+               return -EINVAL;
+
+       cpu->id = id;
+       cpu->lg = container_of((cpu - id), struct lguest, cpus[0]);
+       cpu->lg->nr_cpus++;
+       init_clockdev(cpu);
+
+       return 0;
 }
 
 /*L:020 The initialization write supplies 4 pointer sized (32 or 64 bit)
@@ -92,8 +115,8 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
  * base: The start of the Guest-physical memory inside the Launcher memory.
  *
  * pfnlimit: The highest (Guest-physical) page number the Guest should be
- * allowed to access.  The Launcher has to live in Guest memory, so it sets
- * this to ensure the Guest can't reach it.
+ * allowed to access.  The Guest memory lives inside the Launcher, so it sets
+ * this to ensure the Guest can only reach its own memory.
  *
  * pgdir: The (Guest-physical) address of the top of the initial Guest
  * pagetables (which are set up by the Launcher).
@@ -132,6 +155,11 @@ static int initialize(struct file *file, const unsigned long __user *input)
        lg->mem_base = (void __user *)(long)args[0];
        lg->pfn_limit = args[1];
 
+       /* This is the first cpu */
+       err = lg_cpu_start(&lg->cpus[0], 0, args[3]);
+       if (err)
+               goto release_guest;
+
        /* We need a complete page for the Guest registers: they are accessible
         * to the Guest and we can only grant it access to whole pages. */
        lg->regs_page = get_zeroed_page(GFP_KERNEL);
@@ -153,9 +181,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
         * address. */
        lguest_arch_setup_regs(lg, args[3]);
 
-       /* The timer for lguest's clock needs initialization. */
-       init_clockdev(lg);
-
        /* We keep a pointer to the Launcher task (ie. current task) for when
         * other Guests want to wake this one (inter-Guest I/O). */
        lg->tsk = current;
@@ -182,14 +207,14 @@ static int initialize(struct file *file, const unsigned long __user *input)
 free_regs:
        free_page(lg->regs_page);
 release_guest:
-       memset(lg, 0, sizeof(*lg));
+       kfree(lg);
 unlock:
        mutex_unlock(&lguest_lock);
        return err;
 }
 
 /*L:010 The first operation the Launcher does must be a write.  All writes
- * start with a 32 bit number: for the first write this must be
+ * start with an unsigned long number: for the first write this must be
  * LHREQ_INITIALIZE to set up the Guest.  After that the Launcher can use
  * writes of other values to send interrupts. */
 static ssize_t write(struct file *file, const char __user *in,
@@ -200,14 +225,21 @@ static ssize_t write(struct file *file, const char __user *in,
        struct lguest *lg = file->private_data;
        const unsigned long __user *input = (const unsigned long __user *)in;
        unsigned long req;
+       struct lg_cpu *cpu;
+       unsigned int cpu_id = *off;
 
        if (get_user(req, input) != 0)
                return -EFAULT;
        input++;
 
        /* If you haven't initialized, you must do that first. */
-       if (req != LHREQ_INITIALIZE && !lg)
-               return -EINVAL;
+       if (req != LHREQ_INITIALIZE) {
+               if (!lg || (cpu_id >= lg->nr_cpus))
+                       return -EINVAL;
+               cpu = &lg->cpus[cpu_id];
+               if (!cpu)
+                       return -EINVAL;
+       }
 
        /* Once the Guest is dead, all you can do is read() why it died. */
        if (lg && lg->dead)
@@ -239,6 +271,7 @@ static ssize_t write(struct file *file, const char __user *in,
 static int close(struct inode *inode, struct file *file)
 {
        struct lguest *lg = file->private_data;
+       unsigned int i;
 
        /* If we never successfully initialized, there's nothing to clean up */
        if (!lg)
@@ -247,8 +280,9 @@ static int close(struct inode *inode, struct file *file)
        /* We need the big lock, to protect from inter-guest I/O and other
         * Launchers initializing guests. */
        mutex_lock(&lguest_lock);
-       /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
-       hrtimer_cancel(&lg->hrt);
+       for (i = 0; i < lg->nr_cpus; i++)
+               /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+               hrtimer_cancel(&lg->cpus[i].hrt);
        /* Free up the shadow page tables for the Guest. */
        free_guest_pagetable(lg);
        /* Now all the memory cleanups are done, it's safe to release the
@@ -275,8 +309,7 @@ static int close(struct inode *inode, struct file *file)
  * The Launcher is the Host userspace program which sets up, runs and services
  * the Guest.  In fact, many comments in the Drivers which refer to "the Host"
  * doing things are inaccurate: the Launcher does all the device handling for
- * the Guest.  The Guest can't tell what's done by the the Launcher and what by
- * the Host.
+ * the Guest, but the Guest can't know that.
  *
  * Just to confuse you: to the Host kernel, the Launcher *is* the Guest and we
  * shall see more of that later.