# HG changeset patch
# User cl349@xxxxxxxxxxxxxxxxxxxx
# Node ID 87dec3b9c54609eb913b9776020bf040ecec476c
# Parent 6c8c3df37bfe5f8d1fa29409e454172e1bc29f21
# Parent 3c1cd2486b7fecd5d97378a7d52e5bfb8eb7c718
merge?
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c Fri Aug 19
15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/process.c Fri Aug 19
15:22:05 2005
@@ -115,20 +115,12 @@
/* We don't actually take CPU down, just spin without interrupts. */
static inline void play_dead(void)
{
- /* Ack it */
- __get_cpu_var(cpu_state) = CPU_DEAD;
-
- /* We shouldn't have to disable interrupts while dead, but
- * some interrupts just don't seem to go away, and this makes
- * it "work" for testing purposes. */
/* Death loop */
while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE)
HYPERVISOR_yield();
- local_irq_disable();
__flush_tlb_all();
cpu_set(smp_processor_id(), cpu_online_map);
- local_irq_enable();
}
#else
static inline void play_dead(void)
@@ -156,12 +148,19 @@
rmb();
if (cpu_is_offline(cpu)) {
+ local_irq_disable();
+ /* Ack it. From this point on until
+ we get woken up, we're not allowed
+ to take any locks. In particular,
+ don't printk. */
+ __get_cpu_var(cpu_state) = CPU_DEAD;
#if defined(CONFIG_XEN) && defined(CONFIG_HOTPLUG_CPU)
/* Tell hypervisor to take vcpu down. */
HYPERVISOR_vcpu_down(cpu);
#endif
play_dead();
- }
+ local_irq_enable();
+ }
__get_cpu_var(irq_stat).idle_timestamp = jiffies;
xen_idle();
@@ -791,3 +790,10 @@
sp -= get_random_int() % 8192;
return sp & ~0xf;
}
+
+
+#ifndef CONFIG_X86_SMP
+void _restore_vcpu(void)
+{
+}
+#endif
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c Fri Aug 19
15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c Fri Aug 19
15:22:05 2005
@@ -1616,3 +1616,21 @@
smp_intr_init();
local_setup_timer_irq();
}
+
+DECLARE_PER_CPU(int, timer_irq);
+
+void _restore_vcpu(void)
+{
+ int cpu = smp_processor_id();
+ extern atomic_t vcpus_rebooting;
+
+ /* We are the first thing the vcpu runs when it comes back,
+ and we are supposed to restore the IPIs and timer
+ interrupts etc. When we return, the vcpu's idle loop will
+ start up again. */
+ _bind_virq_to_irq(VIRQ_TIMER, cpu, per_cpu(timer_irq, cpu));
+ _bind_virq_to_irq(VIRQ_DEBUG, cpu, per_cpu(ldebug_irq, cpu));
+ _bind_ipi_to_irq(RESCHEDULE_VECTOR, cpu, per_cpu(resched_irq, cpu) );
+ _bind_ipi_to_irq(CALL_FUNCTION_VECTOR, cpu, per_cpu(callfunc_irq, cpu)
);
+ atomic_dec(&vcpus_rebooting);
+}
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Fri Aug 19 15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Fri Aug 19 15:22:05 2005
@@ -745,7 +745,7 @@
#endif
/* Dynamically-mapped IRQ. */
-static DEFINE_PER_CPU(int, timer_irq);
+DEFINE_PER_CPU(int, timer_irq);
static struct irqaction irq_timer = {
timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer0",
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c
--- a/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c Fri Aug 19 15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/evtchn.c Fri Aug 19 15:22:05 2005
@@ -144,7 +144,7 @@
vcpu_info_t *vcpu_info = &s->vcpu_data[cpu];
vcpu_info->evtchn_upcall_pending = 0;
-
+
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
while ( l1 != 0 )
@@ -158,9 +158,9 @@
l2 &= ~(1 << l2i);
port = (l1i << 5) + l2i;
- if ( (irq = evtchn_to_irq[port]) != -1 )
+ if ( (irq = evtchn_to_irq[port]) != -1 ) {
do_IRQ(irq, regs);
- else
+ } else
evtchn_device_upcall(port);
}
}
@@ -243,6 +243,74 @@
}
spin_unlock(&irq_mapping_update_lock);
+}
+
+/* This is only used when a vcpu from an xm save. The ipi is expected
+ to have been bound before we suspended, and so all of the xenolinux
+ state is set up; we only need to restore the Xen side of things.
+ The irq number has to be the same, but the evtchn number can
+ change. */
+void _bind_ipi_to_irq(int ipi, int vcpu, int irq)
+{
+ evtchn_op_t op;
+ int evtchn;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ op.cmd = EVTCHNOP_bind_ipi;
+ if ( HYPERVISOR_event_channel_op(&op) != 0 )
+ panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, vcpu);
+ evtchn = op.u.bind_ipi.port;
+
+ printk("<0>IPI %d, old evtchn %d, evtchn %d.\n",
+ ipi, per_cpu(ipi_to_evtchn, vcpu)[ipi],
+ evtchn);
+
+ evtchn_to_irq[irq_to_evtchn[irq]] = -1;
+ irq_to_evtchn[irq] = -1;
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_to_evtchn[irq] = evtchn;
+
+ printk("<0>evtchn_to_irq[%d] = %d.\n", evtchn,
+ evtchn_to_irq[evtchn]);
+ per_cpu(ipi_to_evtchn, vcpu)[ipi] = evtchn;
+
+ bind_evtchn_to_cpu(evtchn, vcpu);
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_mask);
+ clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_pending);
+}
+
+void _bind_virq_to_irq(int virq, int cpu, int irq)
+{
+ evtchn_op_t op;
+ int evtchn;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ op.cmd = EVTCHNOP_bind_virq;
+ op.u.bind_virq.virq = virq;
+ if ( HYPERVISOR_event_channel_op(&op) != 0 )
+ panic("Failed to bind virtual IRQ %d\n", virq);
+ evtchn = op.u.bind_virq.port;
+
+ evtchn_to_irq[irq_to_evtchn[irq]] = -1;
+ irq_to_evtchn[irq] = -1;
+
+ evtchn_to_irq[evtchn] = irq;
+ irq_to_evtchn[irq] = evtchn;
+
+ per_cpu(virq_to_irq, cpu)[virq] = irq;
+
+ bind_evtchn_to_cpu(evtchn, cpu);
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_mask);
+ clear_bit(evtchn, (unsigned long *)HYPERVISOR_shared_info->evtchn_pending);
}
int bind_ipi_to_irq(int ipi)
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/kernel/reboot.c
--- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c Fri Aug 19 15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c Fri Aug 19 15:22:05 2005
@@ -16,6 +16,8 @@
#include <asm-xen/queues.h>
#include <asm-xen/xenbus.h>
#include <asm-xen/ctrl_if.h>
+#include <linux/cpu.h>
+#include <linux/kthread.h>
#define SHUTDOWN_INVALID -1
#define SHUTDOWN_POWEROFF 0
@@ -58,10 +60,71 @@
/* Ignore multiple shutdown requests. */
static int shutting_down = SHUTDOWN_INVALID;
-static void __do_suspend(void)
+#ifndef CONFIG_HOTPLUG_CPU
+#define cpu_down(x) (-EOPNOTSUPP)
+#define cpu_up(x) (-EOPNOTSUPP)
+#endif
+
+static void save_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt)
+{
+ int r;
+ int gdt_pages;
+ r = HYPERVISOR_vcpu_pickle(vcpu, ctxt);
+ if (r != 0)
+ panic("pickling vcpu %d -> %d!\n", vcpu, r);
+
+ /* Translate from machine to physical addresses where necessary,
+ so that they can be translated to our new machine address space
+ after resume. libxc is responsible for doing this to vcpu0,
+ but we do it to the others. */
+ gdt_pages = (ctxt->gdt_ents + 511) / 512;
+ ctxt->ctrlreg[3] = machine_to_phys(ctxt->ctrlreg[3]);
+ for (r = 0; r < gdt_pages; r++)
+ ctxt->gdt_frames[r] = mfn_to_pfn(ctxt->gdt_frames[r]);
+}
+
+void _restore_vcpu(int cpu);
+
+atomic_t vcpus_rebooting;
+
+static int restore_vcpu_context(int vcpu, vcpu_guest_context_t *ctxt)
+{
+ int r;
+ int gdt_pages = (ctxt->gdt_ents + 511) / 512;
+
+ /* This is kind of a hack, and implicitly relies on the fact that
+ the vcpu stops in a place where all of the call clobbered
+ registers are already dead. */
+ ctxt->user_regs.esp -= 4;
+ ((unsigned long *)ctxt->user_regs.esp)[0] = ctxt->user_regs.eip;
+ ctxt->user_regs.eip = (unsigned long)_restore_vcpu;
+
+ /* De-canonicalise. libxc handles this for vcpu 0, but we need
+ to do it for the other vcpus. */
+ ctxt->ctrlreg[3] = phys_to_machine(ctxt->ctrlreg[3]);
+ for (r = 0; r < gdt_pages; r++)
+ ctxt->gdt_frames[r] = pfn_to_mfn(ctxt->gdt_frames[r]);
+
+ atomic_set(&vcpus_rebooting, 1);
+ r = HYPERVISOR_boot_vcpu(vcpu, ctxt);
+ if (r != 0) {
+ printk(KERN_EMERG "Failed to reboot vcpu %d (%d)\n", vcpu, r);
+ return -1;
+ }
+
+ /* Make sure we wait for the new vcpu to come up before trying to do
+ anything with it or starting the next one. */
+ while (atomic_read(&vcpus_rebooting))
+ barrier();
+
+ return 0;
+}
+
+static int __do_suspend(void *ignore)
{
int i, j;
suspend_record_t *suspend_record;
+ static vcpu_guest_context_t suspended_cpu_records[NR_CPUS];
/* Hmmm... a cleaner interface to suspend/resume blkdevs would be nice. */
/* XXX SMH: yes it would :-( */
@@ -97,13 +160,63 @@
extern unsigned long max_pfn;
extern unsigned int *pfn_to_mfn_frame_list;
+ cpumask_t prev_online_cpus, prev_present_cpus;
+ int err = 0;
+
+ BUG_ON(smp_processor_id() != 0);
+ BUG_ON(in_interrupt());
+
+#if defined(CONFIG_SMP) && !defined(CONFIG_HOTPLUG_CPU)
+ if (num_online_cpus() > 1) {
+ printk(KERN_WARNING "Can't suspend SMP guests without
CONFIG_HOTPLUG_CPU\n");
+ return -EOPNOTSUPP;
+ }
+#endif
+
suspend_record = (suspend_record_t *)__get_free_page(GFP_KERNEL);
if ( suspend_record == NULL )
goto out;
+ /* Take all of the other cpus offline. We need to be careful not
+ to get preempted between the final test for num_online_cpus()
+ == 1 and disabling interrupts, since otherwise userspace could
+ bring another cpu online, and then we'd be stuffed. At the
+ same time, cpu_down can reschedule, so we need to enable
+ preemption while doing that. This kind of sucks, but should be
+ correct. */
+ /* (We don't need to worry about other cpus bringing stuff up,
+ since by the time num_online_cpus() == 1, there aren't any
+ other cpus) */
+ cpus_clear(prev_online_cpus);
+ preempt_disable();
+ while (num_online_cpus() > 1) {
+ preempt_enable();
+ for_each_online_cpu(i) {
+ if (i == 0)
+ continue;
+ err = cpu_down(i);
+ if (err != 0) {
+ printk(KERN_CRIT "Failed to take all CPUs down: %d.\n", err);
+ goto out_reenable_cpus;
+ }
+ cpu_set(i, prev_online_cpus);
+ }
+ preempt_disable();
+ }
+
suspend_record->nr_pfns = max_pfn; /* final number of pfns */
__cli();
+
+ preempt_enable();
+
+ cpus_clear(prev_present_cpus);
+ for_each_present_cpu(i) {
+ if (i == 0)
+ continue;
+ save_vcpu_context(i, &suspended_cpu_records[i]);
+ cpu_set(i, prev_present_cpus);
+ }
#ifdef __i386__
mm_pin_all();
@@ -132,6 +245,8 @@
memcpy(&suspend_record->resume_info, &xen_start_info,
sizeof(xen_start_info));
+ /* We'll stop somewhere inside this hypercall. When it returns,
+ we'll start resuming after the restore. */
HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
shutting_down = SHUTDOWN_INVALID;
@@ -171,11 +286,26 @@
usbif_resume();
+ for_each_cpu_mask(i, prev_present_cpus) {
+ restore_vcpu_context(i, &suspended_cpu_records[i]);
+ }
+
__sti();
+
+ out_reenable_cpus:
+ for_each_cpu_mask(i, prev_online_cpus) {
+ j = cpu_up(i);
+ if (j != 0) {
+ printk(KERN_CRIT "Failed to bring cpu %d back up (%d).\n",
+ i, j);
+ err = j;
+ }
+ }
out:
if ( suspend_record != NULL )
free_page((unsigned long)suspend_record);
+ return err;
}
static int shutdown_process(void *__unused)
@@ -222,6 +352,18 @@
return 0;
}
+static struct task_struct *kthread_create_on_cpu(int (*f)(void *arg),
+ void *arg,
+ const char *name,
+ int cpu)
+{
+ struct task_struct *p;
+ p = kthread_create(f, arg, name);
+ kthread_bind(p, cpu);
+ wake_up_process(p);
+ return p;
+}
+
static void __shutdown_handler(void *unused)
{
int err;
@@ -234,7 +376,7 @@
}
else
{
- __do_suspend();
+ kthread_create_on_cpu(__do_suspend, NULL, "suspender", 0);
}
}
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/x86_64/kernel/process.c
--- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/process.c Fri Aug 19
15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/process.c Fri Aug 19
15:22:05 2005
@@ -743,3 +743,9 @@
sp -= get_random_int() % 8192;
return sp & ~0xf;
}
+
+#ifndef CONFIG_SMP
+void _restore_vcpu(void)
+{
+}
+#endif
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c
--- a/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c Fri Aug 19
15:21:12 2005
+++ b/linux-2.6-xen-sparse/arch/xen/x86_64/kernel/smpboot.c Fri Aug 19
15:22:05 2005
@@ -1286,4 +1286,10 @@
smp_intr_init();
local_setup_timer_irq();
}
-#endif
+
+void _restore_vcpu(void)
+{
+ /* XXX need to write this */
+}
+
+#endif
diff -r 6c8c3df37bfe -r 87dec3b9c546
linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h
--- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h Fri Aug 19
15:21:12 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/hypercall.h Fri Aug 19
15:22:05 2005
@@ -163,7 +163,7 @@
TRAP_INSTR
: "=a" (ret), "=b" (ign)
: "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_yield)
- : "memory" );
+ : "memory", "ecx" );
return ret;
}
@@ -178,7 +178,7 @@
TRAP_INSTR
: "=a" (ret), "=b" (ign1)
: "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_block)
- : "memory" );
+ : "memory", "ecx" );
return ret;
}
@@ -194,7 +194,7 @@
: "=a" (ret), "=b" (ign1)
: "0" (__HYPERVISOR_sched_op),
"1" (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift))
- : "memory" );
+ : "memory", "ecx" );
return ret;
}
@@ -210,7 +210,7 @@
: "=a" (ret), "=b" (ign1)
: "0" (__HYPERVISOR_sched_op),
"1" (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift))
- : "memory" );
+ : "memory", "ecx" );
return ret;
}
@@ -228,7 +228,7 @@
: "=a" (ret), "=b" (ign1), "=S" (ign2)
: "0" (__HYPERVISOR_sched_op),
"b" (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)),
- "S" (srec) : "memory");
+ "S" (srec) : "memory", "ecx");
return ret;
}
@@ -244,7 +244,7 @@
: "=a" (ret), "=b" (ign1)
: "0" (__HYPERVISOR_sched_op),
"1" (SCHEDOP_shutdown | (SHUTDOWN_crash << SCHEDOP_reasonshift))
- : "memory" );
+ : "memory", "ecx" );
return ret;
}
@@ -529,12 +529,15 @@
{
int ret;
unsigned long ign1;
+ /* Yes, I really do want to clobber edx here: when we resume a
+ vcpu after unpickling a multi-processor domain, it returns
+ here, but clobbers all of the call clobbered registers. */
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret), "=b" (ign1)
: "0" (__HYPERVISOR_sched_op),
"1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift))
- : "memory" );
+ : "memory", "ecx", "edx" );
return ret;
}
@@ -550,8 +553,26 @@
: "=a" (ret), "=b" (ign1)
: "0" (__HYPERVISOR_sched_op),
"1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift))
+ : "memory", "ecx" );
+
+ return ret;
+}
+
+static inline int
+HYPERVISOR_vcpu_pickle(
+ int vcpu, vcpu_guest_context_t *ctxt)
+{
+ int ret;
+ unsigned long ign1, ign2;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret), "=b" (ign1), "=c" (ign2)
+ : "0" (__HYPERVISOR_sched_op),
+ "1" (SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)),
+ "2" (ctxt)
: "memory" );
return ret;
}
+
#endif /* __HYPERCALL_H__ */
diff -r 6c8c3df37bfe -r 87dec3b9c546 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Fri Aug 19 15:21:12 2005
+++ b/xen/arch/x86/domain.c Fri Aug 19 15:22:05 2005
@@ -217,8 +217,16 @@
return xmalloc(struct vcpu);
}
+/* We assume that vcpu 0 is always the last one to be freed in a
+ domain i.e. if v->vcpu_id == 0, the domain should be
+ single-processor. */
void arch_free_vcpu_struct(struct vcpu *v)
{
+ struct vcpu *p;
+ for_each_vcpu(v->domain, p) {
+ if (p->next_in_list == v)
+ p->next_in_list = v->next_in_list;
+ }
xfree(v);
}
@@ -403,7 +411,7 @@
{
if ( ((c->user_regs.cs & 3) == 0) ||
((c->user_regs.ss & 3) == 0) )
- return -EINVAL;
+ return -EINVAL;
}
clear_bit(_VCPUF_fpu_initialised, &v->vcpu_flags);
@@ -457,7 +465,7 @@
if ( !(c->flags & VGCF_VMX_GUEST) )
#endif
if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d,
- PGT_base_page_table) )
+ PGT_base_page_table) )
return -EINVAL;
}
diff -r 6c8c3df37bfe -r 87dec3b9c546 xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Fri Aug 19 15:21:12 2005
+++ b/xen/arch/x86/mm.c Fri Aug 19 15:22:05 2005
@@ -2633,14 +2633,16 @@
if ( entries > FIRST_RESERVED_GDT_ENTRY )
return -EINVAL;
-
+
shadow_sync_all(d);
/* Check the pages in the new GDT. */
- for ( i = 0; i < nr_pages; i++ )
- if ( ((pfn = frames[i]) >= max_page) ||
- !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
+ for ( i = 0; i < nr_pages; i++ ) {
+ pfn = frames[i];
+ if ((pfn >= max_page) ||
+ !get_page_and_type(&frame_table[pfn], d, PGT_gdt_page) )
goto fail;
+ }
/* Tear down the old GDT. */
destroy_gdt(v);
diff -r 6c8c3df37bfe -r 87dec3b9c546 xen/common/event_channel.c
--- a/xen/common/event_channel.c Fri Aug 19 15:21:12 2005
+++ b/xen/common/event_channel.c Fri Aug 19 15:22:05 2005
@@ -588,7 +588,6 @@
long rc = 0;
if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) {
- printf("vcpu %d bad.\n", vcpu);
return -EINVAL;
}
@@ -596,7 +595,6 @@
if ( !port_is_valid(d, port) )
{
- printf("port %d bad.\n", port);
rc = -EINVAL;
goto out;
}
@@ -610,7 +608,6 @@
chn->notify_vcpu_id = vcpu;
break;
default:
- printf("evtchn type %d can't be rebound.\n", chn->state);
rc = -EINVAL;
break;
}
diff -r 6c8c3df37bfe -r 87dec3b9c546 xen/common/schedule.c
--- a/xen/common/schedule.c Fri Aug 19 15:21:12 2005
+++ b/xen/common/schedule.c Fri Aug 19 15:22:05 2005
@@ -38,6 +38,8 @@
#include <xen/mm.h>
#include <public/sched_ctl.h>
+extern void arch_getdomaininfo_ctxt(struct vcpu *,
+ struct vcpu_guest_context *);
/* opt_sched: scheduler - default to SEDF */
static char opt_sched[10] = "sedf";
string_param("sched", opt_sched);
@@ -82,7 +84,8 @@
int i;
SCHED_OP(free_task, d);
- for (i = 0; i < MAX_VIRT_CPUS; i++)
+ /* vcpu 0 has to be the last one destructed. */
+ for (i = MAX_VIRT_CPUS-1; i >= 0; i--)
if ( d->vcpu[i] )
arch_free_vcpu_struct(d->vcpu[i]);
@@ -295,10 +298,36 @@
return 0;
}
+static long do_vcpu_pickle(int vcpu, unsigned long arg)
+{
+ struct vcpu *v;
+ vcpu_guest_context_t *c;
+ int ret = 0;
+
+ if (vcpu >= MAX_VIRT_CPUS)
+ return -EINVAL;
+ v = current->domain->vcpu[vcpu];
+ if (!v)
+ return -ESRCH;
+ /* Don't pickle vcpus which are currently running */
+ if (!test_bit(_VCPUF_down, &v->vcpu_flags)) {
+ return -EBUSY;
+ }
+ c = xmalloc(vcpu_guest_context_t);
+ if (!c)
+ return -ENOMEM;
+ arch_getdomaininfo_ctxt(v, c);
+ if (copy_to_user((vcpu_guest_context_t *)arg,
+ (const vcpu_guest_context_t *)c, sizeof(*c)))
+ ret = -EFAULT;
+ xfree(c);
+ return ret;
+}
+
/*
* Demultiplex scheduler-related hypercalls.
*/
-long do_sched_op(unsigned long op)
+long do_sched_op(unsigned long op, unsigned long arg)
{
long ret = 0;
@@ -332,6 +361,11 @@
case SCHEDOP_vcpu_up:
{
ret = do_vcpu_up((int)(op >> SCHEDOP_vcpushift));
+ break;
+ }
+ case SCHEDOP_vcpu_pickle:
+ {
+ ret = do_vcpu_pickle((int)(op >> SCHEDOP_vcpushift), arg);
break;
}
diff -r 6c8c3df37bfe -r 87dec3b9c546 xen/include/public/xen.h
--- a/xen/include/public/xen.h Fri Aug 19 15:21:12 2005
+++ b/xen/include/public/xen.h Fri Aug 19 15:22:05 2005
@@ -203,6 +203,7 @@
#define SCHEDOP_shutdown 2 /* Stop executing this domain. */
#define SCHEDOP_vcpu_down 3 /* make target VCPU not-runnable. */
#define SCHEDOP_vcpu_up 4 /* make target VCPU runnable. */
+#define SCHEDOP_vcpu_pickle 5 /* save a vcpu's context to memory. */
#define SCHEDOP_cmdmask 255 /* 8-bit command. */
#define SCHEDOP_reasonshift 8 /* 8-bit reason code. (SCHEDOP_shutdown) */
#define SCHEDOP_vcpushift 8 /* 8-bit VCPU target. (SCHEDOP_up|down) */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|