/******************************************************************************
* arch/x86/domain.c
*
* x86-specific domain handling (e.g., register setup and context switching).
*/
/*
* Copyright (C) 1995 Linus Torvalds
*
* Pentium III FXSR, SSE support
* Gareth Hughes <gareth@valinux.com>, May 2000
*/
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <xen/smp.h>
#include <xen/delay.h>
#include <xen/softirq.h>
#include <xen/grant_table.h>
#include <xen/iocap.h>
#include <asm/regs.h>
#include <asm/mc146818rtc.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/desc.h>
#include <asm/i387.h>
#include <asm/mpspec.h>
#include <asm/ldt.h>
#include <xen/irq.h>
#include <xen/event.h>
#include <asm/shadow.h>
#include <xen/console.h>
#include <xen/elf.h>
#include <asm/vmx.h>
#include <asm/msr.h>
#include <xen/kernel.h>
#include <xen/multicall.h>
/* opt_noreboot: If true, machine will need manual reset on error. */
static int opt_noreboot = 0;
boolean_param("noreboot", opt_noreboot);
struct percpu_ctxt {
struct vcpu *curr_vcpu;
unsigned int dirty_segment_mask;
} __cacheline_aligned;
static struct percpu_ctxt percpu_ctxt[NR_CPUS];
static void continue_idle_domain(struct vcpu *v)
{
reset_stack_and_jump(idle_loop);
}
static void continue_nonidle_domain(struct vcpu *v)
{
reset_stack_and_jump(ret_from_intr);
}
static void default_idle(void)
{
local_irq_disable();
if ( !softirq_pending(smp_processor_id()) )
safe_halt();
else
local_irq_enable();
}
void idle_loop(void)
{
int cpu = smp_processor_id();
for ( ; ; )
{
irq_stat[cpu].idle_timestamp = jiffies;
while ( !softirq_pending(cpu) )
{
page_scrub_schedule_work();
default_idle();
}
do_softirq();
}
}
void startup_cpu_idle_loop(void)
{
struct vcpu *v = current;
ASSERT(is_idle_vcpu(v));
cpu_set(smp_processor_id(), v->domain->domain_dirty_cpumask);
cpu_set(smp_processor_id(), v->vcpu_dirty_cpumask);
reset_stack_and_jump(idle_loop);
}
static long no_idt[2];
static int reboot_mode;
static inline void kb_wait(void)
{
int i;
for ( i = 0; i < 0x10000; i++ )
if ( (inb_p(0x64) & 0x02) == 0 )
break;
}
void machine_restart(char * __unused)
{
int i;
if ( opt_noreboot )
{
printk("Reboot disabled on cmdline: require manual reset\n");
for ( ; ; )
safe_halt();
}
watchdog_disable();
console_start_sync();
local_irq_enable();
/* Ensure we are the boot CPU. */
if ( GET_APIC_ID(apic_read(APIC_ID)) != boot_cpu_physical_apicid )
{
smp_call_function((void *)machine_restart, NULL, 1, 0);
for ( ; ; )
safe_halt();
}
/*
* Stop all CPUs and turn off local APICs and the IO-APIC, so
* other OSs see a clean IRQ state.
*/
smp_send_stop();
disable_IO_APIC();
stop_vmx();
/* Rebooting needs to touch the page at absolute address 0. */
*((unsigned short *)__va(0x472)) = reboot_mode;
for ( ; ; )
{
/* Pulse the keyboard reset line. */
for ( i = 0; i < 100; i++ )
{
kb_wait();
udelay(50);
outb(0xfe,0x64); /* pulse reset low */
udelay(50);
}
/* That didn't work - force a triple fault.. */
__asm__ __volatile__("lidt %0": "=m" (no_idt));
__asm__ __volatile__("int3");
}
}
void __attribute__((noreturn)) __machine_halt(void *unused)
{
for ( ; ; )
safe_halt();
}
void machine_halt(void)
{
watchdog_disable();
console_start_sync();
smp_call_function(__machine_halt, NULL, 1, 0);
__machine_halt(NULL);
}
void dump_pageframe_info(struct domain *d)
{
struct pfn_info *page;
printk("Memory pages belonging to domain %u:\n", d->domain_id);
if ( d->tot_pages >= 10 )
{
printk(" DomPage list too long to display\n");
}
else
{
list_for_each_entry ( page, &d->page_list, list )
{
printk(" DomPage %p: mfn=%p, caf=%08x, taf=%" PRtype_info "\n",
_p(page_to_phys(page)), _p(page_to_pfn(page)),
page->count_info, page->u.inuse.type_info);
}
}
list_for_each_entry ( page, &d->xenpage_list, list )
{
printk(" XenPage %p: mfn=%p, caf=%08x, taf=%" PRtype_info "\n",