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'
[palacios.git] / kitten / arch / x86_64 / kernel / xcall.c
diff --git a/kitten/arch/x86_64/kernel/xcall.c b/kitten/arch/x86_64/kernel/xcall.c
new file mode 100644 (file)
index 0000000..9afe497
--- /dev/null
@@ -0,0 +1,137 @@
+#include <lwk/kernel.h>
+#include <lwk/spinlock.h>
+#include <lwk/xcall.h>
+#include <arch/apic.h>
+#include <arch/idt_vectors.h>
+#include <arch/processor.h>
+
+/**
+ * Used to pass data to and synchronize the CPUs targeted by a cross-call.
+ */
+struct xcall_data_struct {
+       void            (*func)(void *info);
+       void *          info;
+       atomic_t        started;
+       atomic_t        finished;
+       bool            wait;
+};
+
+/**
+ * Global cross-call data pointer, protected by xcall_data_lock.
+ */
+static struct xcall_data_struct *xcall_data;
+static DEFINE_SPINLOCK(xcall_data_lock);
+
+/**
+ * x86_64 specific code for carrying out inter-CPU function calls. 
+ * This function should not be called directly. Call xcall_function() instead.
+ *
+ * Arguments:
+ *       [IN] cpu_mask: The target CPUs of the cross-call.
+ *       [IN] func:     The function to execute on each target CPU.
+ *       [IN] info:     Argument to pass to func().
+ *       [IN] wait:     true = wait for cross-call to fully complete.
+ *
+ * Returns:
+ *       Success: 0
+ *       Failure: Error code
+ */
+int
+arch_xcall_function(
+       cpumask_t       cpu_mask,
+       void            (*func)(void *info),
+       void *          info,
+       bool            wait
+)
+{
+       struct xcall_data_struct data;
+       unsigned int num_cpus;
+       unsigned int cpu;
+
+       BUG_ON(irqs_disabled());
+
+       /* Count how many CPUs are being targeted */
+       num_cpus = cpus_weight(cpu_mask);
+       if (!num_cpus)
+               return 0;
+
+       /* Fill in the xcall data structure on our stack */
+       data.func = func;
+       data.info = info;
+       atomic_set(&data.started, 0);
+       if (wait)
+               atomic_set(&data.finished, 0);
+       data.wait = wait;
+
+       /* Spin with IRQs enabled */
+       while (!spin_trylock_irq(&xcall_data_lock))
+               ;
+       /* IRQs are now disabled */
+
+       /* Set the global xcall data pointer */
+       xcall_data = &data;
+       wmb();
+
+       /* Send inter-processor interrupts to the target CPUs */
+       for_each_cpu_mask(cpu, cpu_mask)
+               lapic_send_ipi(cpu, XCALL_FUNCTION_VECTOR);
+
+       /* Wait for initiation responses */
+       while (atomic_read(&data.started) != num_cpus)
+               cpu_relax();
+
+       /* If requested, wait for completion responses */
+       if (wait) {
+               while (atomic_read(&data.finished) != num_cpus)
+                       cpu_relax();
+       }
+       spin_unlock_irq(&xcall_data_lock);
+
+       return 0;
+}
+
+/**
+ * The interrupt handler for inter-CPU function calls.
+ */
+void
+arch_xcall_function_interrupt(struct pt_regs *regs, unsigned int vector)
+{
+       void (*func)(void *info) = xcall_data->func;
+       void *info               = xcall_data->info;
+       int wait                 = xcall_data->wait;
+
+       /* Notify initiating CPU that we've started */
+       mb();
+       atomic_inc(&xcall_data->started);
+
+       /* Execute the cross-call function */
+       (*func)(info);
+
+       /* Notify initiating CPU that the cross-call function has completed */
+       if (wait) {
+               mb();
+               atomic_inc(&xcall_data->finished);
+       }
+}
+
+/**
+ * Sends a reschedule inter-processor interrupt to the target CPU.
+ * This causes the target CPU to call schedule().
+ */
+void
+arch_xcall_reschedule(id_t cpu)
+{
+       lapic_send_ipi(cpu, XCALL_RESCHEDULE_VECTOR);
+}
+
+/**
+ * The interrupt handler for inter-CPU reschedule calls.
+ */
+void
+arch_xcall_reschedule_interrupt(struct pt_regs *regs, unsigned int vector)
+{
+       /*
+        * Nothing to do, schedule() will be automatically
+        * called before returning to user-space
+        */
+}