#include <hypervisor-ifs/network.h>
#include <hypervisor-ifs/block.h>
#include <hypervisor-ifs/hypervisor-if.h>
-
+#include "../../../tools/xend/lib/domain_controller.h"
/*
* a placeholder for the start of day information passed up from the hypervisor
return ret;
}
-static __inline__ int HYPERVISOR_exit(void)
+static inline int HYPERVISOR_shutdown(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_sched_op),
+ "b" (SCHEDOP_stop | (STOPCODE_shutdown << SCHEDOP_reasonshift))
+ : "memory" );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_reboot(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
- "b" (SCHEDOP_exit) : "memory" );
+ "b" (SCHEDOP_stop | (STOPCODE_reboot << SCHEDOP_reasonshift))
+ : "memory" );
return ret;
}
-static __inline__ int HYPERVISOR_stop(unsigned long srec)
+static inline int HYPERVISOR_suspend(unsigned long srec)
{
int ret;
/* NB. On suspend, control software expects a suspend record in %esi. */
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
- "b" (SCHEDOP_stop), "S" (srec) : "memory" );
+ "b" (SCHEDOP_stop | (STOPCODE_suspend << SCHEDOP_reasonshift)),
+ "S" (srec) : "memory" );
return ret;
}
void do_exit(void)
{
printk("do_exit called!\n");
- for ( ;; ) HYPERVISOR_exit();
+ for ( ;; ) HYPERVISOR_shutdown();
}
static void exit_handler(int ev, struct pt_regs *regs) {
do_exit();
/* We really want to get pending console data out before we die. */
extern void xencons_force_flush(void);
xencons_force_flush();
- HYPERVISOR_exit();
+ HYPERVISOR_reboot();
}
void machine_halt(void)
{
- machine_restart(NULL);
+ /* We really want to get pending console data out before we die. */
+ extern void xencons_force_flush(void);
+ xencons_force_flush();
+ HYPERVISOR_shutdown();
}
void machine_power_off(void)
{
- machine_restart(NULL);
+ /* We really want to get pending console data out before we die. */
+ extern void xencons_force_flush(void);
+ xencons_force_flush();
+ HYPERVISOR_shutdown();
}
extern void show_trace(unsigned long* esp);
memcpy(&suspend_record->resume_info, &start_info, sizeof(start_info));
- HYPERVISOR_stop(virt_to_machine(suspend_record) >> PAGE_SHIFT);
+ HYPERVISOR_suspend(virt_to_machine(suspend_record) >> PAGE_SHIFT);
suspending = 0;
return ret;
}
-static inline int HYPERVISOR_exit(void)
+static inline int HYPERVISOR_shutdown(void)
{
int ret;
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
- "b" (SCHEDOP_exit) : "memory" );
+ "b" (SCHEDOP_stop | (STOPCODE_shutdown << SCHEDOP_reasonshift))
+ : "memory" );
return ret;
}
-static inline int HYPERVISOR_stop(unsigned long srec)
+static inline int HYPERVISOR_reboot(void)
+{
+ int ret;
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret) : "0" (__HYPERVISOR_sched_op),
+ "b" (SCHEDOP_stop | (STOPCODE_reboot << SCHEDOP_reasonshift))
+ : "memory" );
+
+ return ret;
+}
+
+static inline int HYPERVISOR_suspend(unsigned long srec)
{
int ret;
/* NB. On suspend, control software expects a suspend record in %esi. */
__asm__ __volatile__ (
TRAP_INSTR
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
- "b" (SCHEDOP_stop), "S" (srec) : "memory" );
+ "b" (SCHEDOP_stop | (STOPCODE_suspend << SCHEDOP_reasonshift)),
+ "S" (srec) : "memory" );
return ret;
}
if ( do_dom0_op(xc_handle, &op) < 0 )
break;
info->domid = (u32)op.u.getdomaininfo.domain;
- info->cpu = op.u.getdomaininfo.processor;
- info->has_cpu = op.u.getdomaininfo.has_cpu;
- info->stopped = (op.u.getdomaininfo.state == DOMSTATE_STOPPED);
+
+ info->cpu =
+ (op.u.getdomaininfo.flags>>DOMFLAGS_CPUSHIFT) & DOMFLAGS_CPUMASK;
+ info->has_cpu =
+ (op.u.getdomaininfo.flags&DOMFLAGS_STATEMASK) == DOMSTATE_RUNNING;
+ info->stopped =
+ (op.u.getdomaininfo.flags&DOMFLAGS_STATEMASK) == DOMSTATE_STOPPED;
+
info->nr_pages = op.u.getdomaininfo.tot_pages;
info->max_memkb = op.u.getdomaininfo.max_pages<<(PAGE_SHIFT-10);
info->shared_info_frame = op.u.getdomaininfo.shared_info_frame;
PERROR("Could not get info on domain");
goto error_out;
}
- if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
+ if ( ((op.u.getdomaininfo.flags&DOMFLAGS_STATEMASK) != DOMSTATE_STOPPED) ||
(ctxt->pt_base != 0) )
{
ERROR("Domain is already constructed");
PERROR("Could not get info on domain");
goto error_out;
}
- if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
+ if ( ((op.u.getdomaininfo.flags&DOMFLAGS_STATEMASK) != DOMSTATE_STOPPED) ||
(op.u.getdomaininfo.ctxt->pt_base != 0) )
{
ERROR("Domain is already constructed");
goto out;
}
- if ( op->u.getdomaininfo.state == DOMSTATE_STOPPED )
+ if ( (op->u.getdomaininfo.flags & DOMFLAGS_STATEMASK) ==
+ DOMSTATE_STOPPED )
{
printf("Domain %u stopped\n",domid);
return 0;
#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */
+/*
+ * Stop codes for SCHEDOP_stop. These are opaque to Xen but interpreted by
+ * control software to determine appropriate action.
+ */
+
+#define STOPCODE_shutdown 0 /* Domain exited normally. Clean up and kill. */
+#define STOPCODE_reboot 1 /* Clean up, kill, and then restart. */
+#define STOPCODE_suspend 2 /* Clean up, save suspend info, kill. */
+
+
/*
* CONTROLLER MESSAGING INTERFACE.
*/
.section __ex_table,"a"
.align 4
- .long FAULT1, kill_domain_fixup3 # Fault writing to ring-1 stack
- .long FAULT2, kill_domain_fixup3 # Fault writing to ring-1 stack
- .long FAULT3, kill_domain_fixup3 # Fault writing to ring-1 stack
- .long FAULT4, kill_domain_fixup3 # Fault writing to ring-1 stack
- .long FAULT5, kill_domain_fixup1 # Fault executing failsafe iret
- .long FAULT6, kill_domain_fixup2 # Fault loading ring-1 stack selector
- .long FAULT7, kill_domain_fixup2 # Fault writing to ring-1 stack
- .long FAULT8, kill_domain_fixup2 # Fault writing to ring-1 stack
- .long FAULT9, kill_domain_fixup2 # Fault loading ring-1 stack selector
- .long FAULT10,kill_domain_fixup2 # Fault writing to ring-1 stack
- .long FAULT11,kill_domain_fixup2 # Fault writing to ring-1 stack
- .long FAULT12,kill_domain_fixup2 # Fault writing to ring-1 stack
- .long FAULT13,kill_domain_fixup3 # Fault writing to ring-1 stack
- .long FAULT14,kill_domain_fixup3 # Fault writing to ring-1 stack
+ .long FAULT1, crash_domain_fixup3 # Fault writing to ring-1 stack
+ .long FAULT2, crash_domain_fixup3 # Fault writing to ring-1 stack
+ .long FAULT3, crash_domain_fixup3 # Fault writing to ring-1 stack
+ .long FAULT4, crash_domain_fixup3 # Fault writing to ring-1 stack
+ .long FAULT5, crash_domain_fixup1 # Fault executing failsafe iret
+ .long FAULT6, crash_domain_fixup2 # Fault loading ring-1 stack selector
+ .long FAULT7, crash_domain_fixup2 # Fault writing to ring-1 stack
+ .long FAULT8, crash_domain_fixup2 # Fault writing to ring-1 stack
+ .long FAULT9, crash_domain_fixup2 # Fault loading ring-1 stack selector
+ .long FAULT10,crash_domain_fixup2 # Fault writing to ring-1 stack
+ .long FAULT11,crash_domain_fixup2 # Fault writing to ring-1 stack
+ .long FAULT12,crash_domain_fixup2 # Fault writing to ring-1 stack
+ .long FAULT13,crash_domain_fixup3 # Fault writing to ring-1 stack
+ .long FAULT14,crash_domain_fixup3 # Fault writing to ring-1 stack
.previous
# This handler kills domains which experience unrecoverable faults.
.section .fixup,"ax"
-kill_domain_fixup1:
+crash_domain_fixup1:
subl $4,%esp
SAVE_ALL
- jmp kill_domain
-kill_domain_fixup2:
+ jmp crash_domain
+crash_domain_fixup2:
addl $4,%esp
-kill_domain_fixup3:
+crash_domain_fixup3:
pushl %ss
popl %ds
- jmp kill_domain
+ jmp crash_domain
.previous
ALIGN
case DOM0_GETDOMAININFO:
{
- struct task_struct *p;
- u_long flags;
- int i;
+ full_execution_context_t *c;
+ struct task_struct *p;
+ unsigned long flags;
+ int i;
- read_lock_irqsave (&tasklist_lock, flags);
+ read_lock_irqsave(&tasklist_lock, flags);
for_each_domain ( p )
{
break;
}
- if ( p == NULL )
+ if ( (p == NULL) || (p->state == TASK_DYING) )
{
ret = -ESRCH;
goto gdi_out;
else
{
op->u.getdomaininfo.domain = p->domain;
- strcpy (op->u.getdomaininfo.name, p->name);
- op->u.getdomaininfo.processor = p->processor;
- op->u.getdomaininfo.has_cpu = p->has_cpu;
- op->u.getdomaininfo.state = DOMSTATE_ACTIVE;
- if ( (p->state == TASK_STOPPED) || (p->state == TASK_DYING) )
- op->u.getdomaininfo.state = DOMSTATE_STOPPED;
+ strcpy(op->u.getdomaininfo.name, p->name);
+
+ if ( p->state == TASK_RUNNING )
+ op->u.getdomaininfo.flags =
+ p->has_cpu ? DOMSTATE_RUNNING : DOMSTATE_RUNNABLE;
+ else if ( (p->state == TASK_INTERRUPTIBLE) ||
+ (p->state == TASK_UNINTERRUPTIBLE) )
+ op->u.getdomaininfo.flags = DOMSTATE_BLOCKED;
+ else if ( p->state == TASK_PAUSED )
+ op->u.getdomaininfo.flags = DOMSTATE_PAUSED;
+ else if ( p->state == TASK_CRASHED )
+ op->u.getdomaininfo.flags = DOMSTATE_CRASHED;
+ else
+ op->u.getdomaininfo.flags = DOMSTATE_STOPPED;
+ op->u.getdomaininfo.flags |= p->processor << DOMFLAGS_CPUSHIFT;
+ op->u.getdomaininfo.flags |= p->stop_code << DOMFLAGS_GUESTSHIFT;
+
op->u.getdomaininfo.hyp_events = p->hyp_events;
op->u.getdomaininfo.tot_pages = p->tot_pages;
op->u.getdomaininfo.max_pages = p->max_pages;
op->u.getdomaininfo.shared_info_frame =
__pa(p->shared_info) >> PAGE_SHIFT;
- if ( p->state == TASK_STOPPED && op->u.getdomaininfo.ctxt )
+ if ( (p->state == TASK_STOPPED) &&
+ (op->u.getdomaininfo.ctxt != NULL) )
{
- full_execution_context_t *c=NULL;
-
if ( (c = kmalloc(sizeof(*c), GFP_KERNEL)) == NULL )
{
- ret= -ENOMEM;
+ ret = -ENOMEM;
goto gdi_out;
}
c->failsafe_callback_eip =
p->failsafe_address;
- if( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) )
- {
+ if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) )
ret = -EINVAL;
- }
- if (c) kfree(c);
+ if ( c != NULL )
+ kfree(c);
}
}
gdi_out:
read_unlock_irqrestore(&tasklist_lock, flags);
-
}
break;
}
-void kill_domain_with_errmsg(const char *err)
-{
- printk("DOM%u FATAL ERROR: %s\n", current->domain, err);
- kill_domain();
-}
-
-
void __kill_domain(struct task_struct *p)
{
int i;
if ( (p = find_domain_by_id(dom)) == NULL )
return -ESRCH;
- if ( p->state == TASK_STOPPED )
+ if ( (p->state == TASK_STOPPED) || (p->state == TASK_CRASHED) )
__kill_domain(p);
else if ( force )
send_hyp_event(p, _HYP_EVENT_DIE);
return 0;
}
-void stop_domain(void)
+
+void crash_domain(void)
{
+ struct task_struct *p;
+
+ set_current_state(TASK_CRASHED);
+
+ p = find_domain_by_id(0);
+ send_guest_virq(p, VIRQ_DOM_EXC);
+ put_task_struct(p);
+
+ __enter_scheduler();
+ BUG();
+}
+
+
+void stop_domain(u8 reason)
+{
+ struct task_struct *p;
+
+ current->stop_code = reason;
memcpy(¤t->shared_info->execution_context,
get_execution_context(),
sizeof(execution_context_t));
wmb(); /* All CPUs must see saved info in state TASK_STOPPED. */
set_current_state(TASK_STOPPED);
- /* OK, this is grim, but helps speed up live migrate. When a domain stops,
- kick Dom0 */
- {
- struct task_struct *p;
- guest_schedule_to_run( p = find_domain_by_id(0ULL) );
- put_task_struct(p);
- }
+ p = find_domain_by_id(0);
+ send_guest_virq(p, VIRQ_DOM_EXC);
+ put_task_struct(p);
__enter_scheduler();
}
{
long ret = 0;
- switch( op )
+ switch ( op & SCHEDOP_cmdmask )
{
case SCHEDOP_yield:
break;
}
- case SCHEDOP_exit:
- {
- DPRINTK("DOM%u killed itself!\n", current->domain);
- DPRINTK(" EIP == %08lx\n", get_execution_context()->eip);
- kill_domain();
- break;
- }
-
case SCHEDOP_stop:
{
- DPRINTK("DOM%u stopped itself!\n", current->domain);
- DPRINTK(" EIP == %08lx\n", get_execution_context()->eip);
- stop_domain();
+ stop_domain((u8)(op >> SCHEDOP_reasonshift));
break;
}
/*
- * sched_pause_sync - synchronously pause a domain's execution
- * XXXX This is horibly broken -- here just as a place holder at present,
- * do not use.
+ * sched_pause_sync - synchronously pause a domain's execution.
+ * XXXX This is horribly broken -- here just as a place holder at present,
+ * do not use.
*/
void sched_pause_sync(struct task_struct *p)
{
* This makes sure that old versions of dom0 tools will stop working in a
* well-defined way (rather than crashing the machine, for instance).
*/
-#define DOM0_INTERFACE_VERSION 0xAAAA000E
+#define DOM0_INTERFACE_VERSION 0xAAAA000F
#define MAX_DOMAIN_NAME 16
#define DOM0_GETDOMAININFO 12
typedef struct {
/* IN variables. */
- domid_t domain; /* 0 */
- u32 __pad;
- full_execution_context_t *ctxt; /* 8 */
- MEMORY_PADDING;
+ domid_t domain; /* 0 */ /* NB. IN/OUT variable. */
/* OUT variables. */
- u8 name[MAX_DOMAIN_NAME]; /* 16 */
- u32 processor; /* 32 */
- u32 has_cpu; /* 36 */
-#define DOMSTATE_ACTIVE 0
-#define DOMSTATE_STOPPED 1
- u32 state; /* 40 */
- u32 hyp_events; /* 44 */
- u32 tot_pages; /* 48 */
- u32 max_pages; /* 52 */
- u64 cpu_time; /* 56 */
- memory_t shared_info_frame; /* 64: MFN of shared_info struct */
+#define DOMSTATE_CRASHED 0 /* Crashed domain; frozen for postmortem. */
+#define DOMSTATE_STOPPED 1 /* Domain voluntarily halted it execution. */
+#define DOMSTATE_PAUSED 2 /* Currently paused (forced non-schedulable). */
+#define DOMSTATE_BLOCKED 3 /* Currently blocked pending a wake-up event. */
+#define DOMSTATE_RUNNABLE 4 /* Currently runnable. */
+#define DOMSTATE_RUNNING 5 /* Currently running. */
+#define DOMFLAGS_STATEMASK 7 /* One of the DOMSTATE_??? values. */
+#define DOMFLAGS_STATESHIFT 0
+#define DOMFLAGS_CPUMASK 255 /* CPU to which this domain is bound. */
+#define DOMFLAGS_CPUSHIFT 3
+#define DOMFLAGS_GUESTMASK 255 /* DOMSTATE_STOPPED -> Guest-supplied code. */
+#define DOMFLAGS_GUESTSHIFT 11
+ u32 flags; /* 4 */
+ u8 name[MAX_DOMAIN_NAME]; /* 8 */
+ full_execution_context_t *ctxt; /* 24 */ /* NB. IN/OUT variable. */
+ MEMORY_PADDING;
+ memory_t tot_pages; /* 32 */
+ MEMORY_PADDING;
+ memory_t max_pages; /* 40 */
+ MEMORY_PADDING;
+ memory_t shared_info_frame; /* 48: MFN of shared_info struct */
MEMORY_PADDING;
-} PACKED dom0_getdomaininfo_t; /* 72 bytes */
+ u64 cpu_time; /* 56 */
+ u32 hyp_events; /* 64 */
+} PACKED dom0_getdomaininfo_t; /* 68 bytes */
#define DOM0_BUILDDOMAIN 13
typedef struct {
u32 cmd; /* 0 */
u32 interface_version; /* 4 */ /* DOM0_INTERFACE_VERSION */
union { /* 8 */
- u32 dummy[14]; /* 56 bytes */
+ u32 dummy[18]; /* 72 bytes */
dom0_createdomain_t createdomain;
dom0_startdomain_t startdomain;
dom0_stopdomain_t stopdomain;
dom0_setdomainmaxmem_t setdomainmaxmem;
dom0_getpageframeinfo2_t getpageframeinfo2;
} PACKED u;
-} PACKED dom0_op_t; /* 64 bytes */
+} PACKED dom0_op_t; /* 80 bytes */
#endif /* __DOM0_OPS_H__ */
*
* Virtual interrupts that a guest OS may receive from the hypervisor.
*/
-#define VIRQ_BLKDEV 0 /* A block device response has been queued. */
+#define VIRQ_BLKDEV 0 /* (OBS) A block device response has been queued. */
#define VIRQ_TIMER 1 /* A timeout has been updated. */
-#define VIRQ_DIE 2 /* OS is about to be killed. Clean up please! */
+#define VIRQ_DIE 2 /* (OBS) OS is about to be killed. Clean up! */
#define VIRQ_DEBUG 3 /* Request guest to dump debug info (gross!) */
-#define VIRQ_NET 4 /* There are packets for transmission. */
-#define VIRQ_PS2 5 /* PS/2 keyboard or mouse event(s) */
-#define VIRQ_STOP 6 /* Prepare for stopping and possible pickling */
+#define VIRQ_NET 4 /* (OBS) There are packets for transmission. */
+#define VIRQ_PS2 5 /* (OBS) PS/2 keyboard or mouse event(s) */
+#define VIRQ_STOP 6 /* (OBS) Prepare for stopping and pickling */
#define VIRQ_EVTCHN 7 /* Event pending on an event channel */
-#define VIRQ_VBD_UPD 8 /* Event to signal VBDs should be reprobed */
-#define VIRQ_CONSOLE 9 /* This is only for domain-0 initial console. */
-#define VIRQ_PHYSIRQ 10 /* Event to signal pending physical IRQs. */
+#define VIRQ_VBD_UPD 8 /* (OBS) Event to signal VBDs should be reprobed */
+#define VIRQ_CONSOLE 9 /* (DOM0) bytes received on master console. */
+#define VIRQ_PHYSIRQ 10 /* Pending physical IRQs. */
#define VIRQ_MISDIRECT 11 /* Catch-all virtual interrupt. */
-#define NR_VIRQS 12
+#define VIRQ_DOM_EXC 12 /* (DOM0) Exceptional event for some domain. */
+#define NR_VIRQS 13
/*
* MMU-UPDATE REQUESTS
*/
#define SCHEDOP_yield 0 /* Give up the CPU voluntarily. */
#define SCHEDOP_block 1 /* Block until an event is received. */
-#define SCHEDOP_exit 3 /* Exit and kill this domain. */
#define SCHEDOP_stop 4 /* Stop executing this domain. */
+#define SCHEDOP_cmdmask 255 /* 8-bit command. */
+#define SCHEDOP_reasonshift 8 /* 8-bit stop code. (SCHEDOP_stop only) */
/*
* Commands to HYPERVISOR_console_io().
struct list_head run_list;
int has_cpu;
int state; /* current run state */
+ int stop_code; /* stop code from OS (if TASK_STOPPED). */
int cpupinned; /* true if pinned to curent CPU */
s_time_t lastschd; /* time this domain was last scheduled */
s_time_t lastdeschd; /* time this domain was last descheduled */
#define TASK_STOPPED 4
#define TASK_DYING 8
#define TASK_PAUSED 16
+#define TASK_CRASHED 32
#include <asm/uaccess.h> /* for KERNEL_DS */
extern void release_task(struct task_struct *);
extern void __kill_domain(struct task_struct *p);
extern void kill_domain(void);
-extern void kill_domain_with_errmsg(const char *err);
extern long kill_other_domain(domid_t dom, int force);
-extern void stop_domain(void);
+extern void stop_domain(u8 reason);
extern long stop_other_domain(domid_t dom);
/* arch/process.c */