From 7323460e1922ad6c76d8161e9d6dc0065944b35c Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:09 -0700 Subject: [PATCH 001/282] [IA64] MCA support - patch for MCA handler Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/linux-xen/mca.c | 342 +++++++++++++++++++++++++++++++--- 1 file changed, 316 insertions(+), 26 deletions(-) diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c index 64151f3a4e..261e7a0174 100644 --- a/xen/arch/ia64/linux-xen/mca.c +++ b/xen/arch/ia64/linux-xen/mca.c @@ -81,6 +81,9 @@ #include #include #include +#include +#include +#include #endif #if defined(IA64_MCA_DEBUG_INFO) @@ -108,18 +111,27 @@ unsigned long __per_cpu_mca[NR_CPUS]; /* In mca_asm.S */ extern void ia64_monarch_init_handler (void); extern void ia64_slave_init_handler (void); +#ifdef XEN +extern void setup_vector (unsigned int vec, struct irqaction *action); +#define setup_irq(irq, action) setup_vector(irq, action) +#endif static ia64_mc_info_t ia64_mc_info; -#ifndef XEN #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ #define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */ #define CPE_HISTORY_LENGTH 5 #define CMC_HISTORY_LENGTH 5 +#ifndef XEN static struct timer_list cpe_poll_timer; static struct timer_list cmc_poll_timer; +#else +#define mod_timer(timer, expires) set_timer(timer, expires) +static struct timer cpe_poll_timer; +static struct timer cmc_poll_timer; +#endif /* * This variable tells whether we are currently in polling mode. * Start with this in the wrong state so we won't play w/ timers @@ -136,11 +148,9 @@ static int cmc_polling_enabled = 1; static int cpe_poll_enabled = 1; extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe); -#endif /* !XEN */ static int mca_init; -#ifndef XEN /* * IA64_MCA log support */ @@ -157,11 +167,24 @@ typedef struct ia64_state_log_s static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; +#ifndef XEN #define IA64_LOG_ALLOCATE(it, size) \ {ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ (ia64_err_rec_t *)alloc_bootmem(size); \ ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ (ia64_err_rec_t *)alloc_bootmem(size);} +#else +#define IA64_LOG_ALLOCATE(it, size) \ + do { \ + unsigned int pageorder; \ + pageorder = get_order_from_bytes(sizeof(struct ia64_mca_cpu)); \ + ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_xenheap_pages(pageorder); \ + ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)] = \ + (ia64_err_rec_t *)alloc_xenheap_pages(pageorder); \ + } while(0) +#endif + #define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock) #define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s) #define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s) @@ -176,6 +199,12 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; #define IA64_LOG_CURR_BUFFER(it) (void *)((ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)])) #define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count +#ifdef XEN +struct list_head sal_queue[IA64_MAX_LOG_TYPES]; +sal_log_record_header_t *sal_record = NULL; +DEFINE_SPINLOCK(sal_queue_lock); +#endif + /* * ia64_log_init * Reset the OS ia64 log buffer @@ -200,8 +229,19 @@ ia64_log_init(int sal_info_type) IA64_LOG_ALLOCATE(sal_info_type, max_size); memset(IA64_LOG_CURR_BUFFER(sal_info_type), 0, max_size); memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, max_size); + +#ifdef XEN + if (sal_record == NULL) { + unsigned int pageorder; + pageorder = get_order_from_bytes(max_size); + sal_record = (sal_log_record_header_t *) + alloc_xenheap_pages(pageorder); + BUG_ON(sal_record == NULL); + } +#endif } +#ifndef XEN /* * ia64_log_get * @@ -277,16 +317,160 @@ ia64_mca_log_sal_error_record(int sal_info_type) if (rh->severity == sal_log_severity_corrected) ia64_sal_clear_state_info(sal_info_type); } +#else /* !XEN */ +/* + * ia64_log_queue + * + * Get the current MCA log from SAL and copy it into the OS log buffer. + * + * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) + * Outputs : size (total record length) + * *buffer (ptr to error record) + * + */ +static u64 +ia64_log_queue(int sal_info_type, int virq) +{ + sal_log_record_header_t *log_buffer; + u64 total_len = 0; + int s; + sal_queue_entry_t *e; + unsigned long flags; + + IA64_LOG_LOCK(sal_info_type); + + /* Get the process state information */ + log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); + + total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); + + if (total_len) { + int queue_type; + + spin_lock_irqsave(&sal_queue_lock, flags); + + if (sal_info_type == SAL_INFO_TYPE_MCA && virq == VIRQ_MCA_CMC) + queue_type = SAL_INFO_TYPE_CMC; + else + queue_type = sal_info_type; + + e = xmalloc(sal_queue_entry_t); + BUG_ON(e == NULL); + e->cpuid = smp_processor_id(); + e->sal_info_type = sal_info_type; + e->vector = IA64_CMC_VECTOR; + e->virq = virq; + e->length = total_len; + + list_add_tail(&e->list, &sal_queue[queue_type]); + spin_unlock_irqrestore(&sal_queue_lock, flags); + + IA64_LOG_INDEX_INC(sal_info_type); + IA64_LOG_UNLOCK(sal_info_type); + if (sal_info_type != SAL_INFO_TYPE_MCA && + sal_info_type != SAL_INFO_TYPE_INIT) { + IA64_MCA_DEBUG("%s: SAL error record type %d retrieved. " + "Record length = %ld\n", __FUNCTION__, + sal_info_type, total_len); + } + return total_len; + } else { + IA64_LOG_UNLOCK(sal_info_type); + return 0; + } +} +#endif /* !XEN */ /* * platform dependent error handling */ -#endif /* !XEN */ #ifndef PLATFORM_MCA_HANDLERS -#ifndef XEN #ifdef CONFIG_ACPI +#ifdef XEN +/** + * Copy from linux/include/asm-generic/bug.h + */ +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + +/** + * Copy from linux/kernel/irq/manage.c + * + * disable_irq_nosync - disable an irq without waiting + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. Disables and Enables are + * nested. + * Unlike disable_irq(), this function does not ensure existing + * instances of the IRQ handler have completed before returning. + * + * This function may be called from IRQ context. + */ +void disable_irq_nosync(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + spin_lock_irqsave(&desc->lock, flags); + if (!desc->depth++) { + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + spin_unlock_irqrestore(&desc->lock, flags); +} + +/** + * Copy from linux/kernel/irq/manage.c + * + * enable_irq - enable handling of an irq + * @irq: Interrupt to enable + * + * Undoes the effect of one call to disable_irq(). If this + * matches the last disable, processing of interrupts on this + * IRQ line is re-enabled. + * + * This function may be called from IRQ context. + */ +void enable_irq(unsigned int irq) +{ + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + if (irq >= NR_IRQS) + return; + + spin_lock_irqsave(&desc->lock, flags); + switch (desc->depth) { + case 0: + WARN_ON(1); + break; + case 1: { + unsigned int status = desc->status & ~IRQ_DISABLED; + + desc->status = status; + if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { + desc->status = status | IRQ_REPLAY; + hw_resend_irq(desc->handler,irq); + } + desc->handler->enable(irq); + /* fall-through */ + } + default: + desc->depth--; + } + spin_unlock_irqrestore(&desc->lock, flags); +} +#endif /* XEN */ + int cpe_vector = -1; static irqreturn_t @@ -302,8 +486,15 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); +#ifndef XEN /* Get the CPE error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); +#else + /* CPE error does not inform to dom0 but the following codes are + reserved for future implementation */ +/* ia64_log_queue(SAL_INFO_TYPE_CPE, VIRQ_MCA_CPE); */ +/* send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CPE); */ +#endif spin_lock(&cpe_history_lock); if (!cpe_poll_enabled && cpe_vector >= 0) { @@ -345,7 +536,6 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) } #endif /* CONFIG_ACPI */ -#endif /* !XEN */ static void show_min_state (pal_min_state_area_t *minstate) @@ -593,7 +783,6 @@ init_handler_platform (pal_min_state_area_t *ms, while (1); /* hang city if no debugger */ } -#ifndef XEN #ifdef CONFIG_ACPI /* * ia64_mca_register_cpev @@ -624,9 +813,7 @@ ia64_mca_register_cpev (int cpev) } #endif /* CONFIG_ACPI */ -#endif /* !XEN */ #endif /* PLATFORM_MCA_HANDLERS */ -#ifndef XEN /* * ia64_mca_cmc_vector_setup @@ -713,6 +900,7 @@ ia64_mca_cmc_vector_enable (void *dummy) __FUNCTION__, smp_processor_id(), cmcv.cmcv_vector); } +#ifndef XEN /* * ia64_mca_cmc_vector_disable_keventd * @@ -736,6 +924,7 @@ ia64_mca_cmc_vector_enable_keventd(void *unused) { on_each_cpu(ia64_mca_cmc_vector_enable, NULL, 1, 0); } +#endif /* !XEN */ /* * ia64_mca_wakeup_ipi_wait @@ -887,15 +1076,26 @@ ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs) static void ia64_return_to_sal_check(int recover) { +#ifdef XEN + int cpu = smp_processor_id(); +#endif /* Copy over some relevant stuff from the sal_to_os_mca_handoff * so that it can be used at the time of os_mca_to_sal_handoff */ +#ifdef XEN + ia64_os_to_sal_handoff_state.imots_sal_gp = + ia64_sal_to_os_handoff_state[cpu].imsto_sal_gp; + + ia64_os_to_sal_handoff_state.imots_sal_check_ra = + ia64_sal_to_os_handoff_state[cpu].imsto_sal_check_ra; +#else ia64_os_to_sal_handoff_state.imots_sal_gp = ia64_sal_to_os_handoff_state.imsto_sal_gp; ia64_os_to_sal_handoff_state.imots_sal_check_ra = ia64_sal_to_os_handoff_state.imsto_sal_check_ra; +#endif if (recover) ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED; @@ -905,8 +1105,13 @@ ia64_return_to_sal_check(int recover) /* Default = tell SAL to return to same context */ ia64_os_to_sal_handoff_state.imots_context = IA64_MCA_SAME_CONTEXT; +#ifdef XEN + ia64_os_to_sal_handoff_state.imots_new_min_state = + (u64 *)ia64_sal_to_os_handoff_state[cpu].pal_min_state; +#else ia64_os_to_sal_handoff_state.imots_new_min_state = (u64 *)ia64_sal_to_os_handoff_state.pal_min_state; +#endif } @@ -954,27 +1159,44 @@ EXPORT_SYMBOL(ia64_unreg_MCA_extension); void ia64_mca_ucmc_handler(void) { +#ifdef XEN + int cpu = smp_processor_id(); + pal_processor_state_info_t *psp = (pal_processor_state_info_t *) + &ia64_sal_to_os_handoff_state[cpu].proc_state_param; +#else pal_processor_state_info_t *psp = (pal_processor_state_info_t *) &ia64_sal_to_os_handoff_state.proc_state_param; +#endif int recover; +#ifndef XEN /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA); +#else + ia64_log_queue(SAL_INFO_TYPE_MCA, VIRQ_MCA_CMC); + send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CMC); +#endif /* TLB error is only exist in this SAL error record */ recover = (psp->tc && !(psp->cc || psp->bc || psp->rc || psp->uc)) /* other error recovery */ +#ifndef XEN || (ia64_mca_ucmc_extension && ia64_mca_ucmc_extension( IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA), &ia64_sal_to_os_handoff_state, &ia64_os_to_sal_handoff_state)); +#else + ; +#endif +#ifndef XEN if (recover) { sal_log_record_header_t *rh = IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_MCA); rh->severity = sal_log_severity_corrected; ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA); } +#endif /* * Wakeup all the processors which are spinning in the rendezvous * loop. @@ -985,8 +1207,10 @@ ia64_mca_ucmc_handler(void) ia64_return_to_sal_check(recover); } +#ifndef XEN static DECLARE_WORK(cmc_disable_work, ia64_mca_cmc_vector_disable_keventd, NULL); static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd, NULL); +#endif /* * ia64_mca_cmc_int_handler @@ -1016,8 +1240,13 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) /* SAL spec states this should run w/ interrupts enabled */ local_irq_enable(); +#ifndef XEN /* Get the CMC error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC); +#else + ia64_log_queue(SAL_INFO_TYPE_CMC, VIRQ_MCA_CMC); + send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CMC); +#endif spin_lock(&cmc_history_lock); if (!cmc_polling_enabled) { @@ -1034,7 +1263,12 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs) cmc_polling_enabled = 1; spin_unlock(&cmc_history_lock); +#ifndef XEN /* XXX FIXME */ schedule_work(&cmc_disable_work); +#else + cpumask_raise_softirq(cpu_online_map, + CMC_DISABLE_SOFTIRQ); +#endif /* * Corrected errors will still be corrected, but @@ -1083,7 +1317,9 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) if (start_count == -1) start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC); +#ifndef XEN ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs); +#endif for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); @@ -1094,7 +1330,12 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) if (start_count == IA64_LOG_COUNT(SAL_INFO_TYPE_CMC)) { printk(KERN_WARNING "Returning to interrupt driven CMC handler\n"); +#ifndef XEN /* XXX FIXME */ schedule_work(&cmc_enable_work); +#else + cpumask_raise_softirq(cpu_online_map, + CMC_ENABLE_SOFTIRQ); +#endif cmc_polling_enabled = 0; } else { @@ -1104,7 +1345,6 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) start_count = -1; } - return IRQ_HANDLED; } @@ -1118,7 +1358,11 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) * */ static void +#ifndef XEN ia64_mca_cmc_poll (unsigned long dummy) +#else +ia64_mca_cmc_poll (void *dummy) +#endif { /* Trigger a CMC interrupt cascade */ platform_send_ipi(first_cpu(cpu_online_map), IA64_CMCP_VECTOR, IA64_IPI_DM_INT, 0); @@ -1153,7 +1397,9 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) if (start_count == -1) start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE); +#ifndef XEN ia64_mca_cpe_int_handler(cpe_irq, arg, ptregs); +#endif for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); @@ -1180,7 +1426,6 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) mod_timer(&cpe_poll_timer, jiffies + poll_time); start_count = -1; } - return IRQ_HANDLED; } @@ -1195,14 +1440,17 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) * */ static void +#ifndef XEN ia64_mca_cpe_poll (unsigned long dummy) +#else +ia64_mca_cpe_poll (void *dummy) +#endif { /* Trigger a CPE interrupt cascade */ platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); } #endif /* CONFIG_ACPI */ -#endif /* !XEN */ /* * C portion of the OS INIT handler @@ -1248,7 +1496,6 @@ ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) init_handler_platform(ms, pt, sw); /* call platform specific routines */ } -#ifndef XEN static int __init ia64_mca_disable_cpe_polling(char *str) { @@ -1260,42 +1507,53 @@ __setup("disable_cpe_poll", ia64_mca_disable_cpe_polling); static struct irqaction cmci_irqaction = { .handler = ia64_mca_cmc_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cmc_hndlr" }; static struct irqaction cmcp_irqaction = { .handler = ia64_mca_cmc_int_caller, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cmc_poll" }; static struct irqaction mca_rdzv_irqaction = { .handler = ia64_mca_rendez_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "mca_rdzv" }; static struct irqaction mca_wkup_irqaction = { .handler = ia64_mca_wakeup_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "mca_wkup" }; #ifdef CONFIG_ACPI static struct irqaction mca_cpe_irqaction = { .handler = ia64_mca_cpe_int_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cpe_hndlr" }; static struct irqaction mca_cpep_irqaction = { .handler = ia64_mca_cpe_int_caller, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "cpe_poll" }; #endif /* CONFIG_ACPI */ -#endif /* !XEN */ /* Do per-CPU MCA-related initialization. */ @@ -1329,6 +1587,13 @@ ia64_mca_cpu_init(void *cpu_data) #endif } } +#ifdef XEN + else { + int i; + for (i = 0; i < IA64_MAX_LOG_TYPES; i++) + ia64_log_queue(i, 0); + } +#endif /* * The MCA info structure was allocated earlier and its @@ -1395,18 +1660,15 @@ ia64_mca_init(void) ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; -#ifdef XEN - s64 rc; - - slave_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; - - IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); -#else int i; s64 rc; struct ia64_sal_retval isrv; u64 timeout = IA64_MCA_RENDEZ_TIMEOUT; /* platform specific */ +#ifdef XEN + slave_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; +#endif + IA64_MCA_DEBUG("%s: begin\n", __FUNCTION__); /* Clear the Rendez checkin flag for all cpus */ @@ -1451,7 +1713,6 @@ ia64_mca_init(void) } IA64_MCA_DEBUG("%s: registered MCA rendezvous spinloop and wakeup mech.\n", __FUNCTION__); -#endif /* !XEN */ ia64_mc_info.imi_mca_handler = ia64_tpa(mca_hldlr_ptr->fp); /* @@ -1503,7 +1764,6 @@ ia64_mca_init(void) IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __FUNCTION__); -#ifndef XEN /* * Configure the CMCI/P vector and handler. Interrupts for CMC are * per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c). @@ -1531,13 +1791,26 @@ ia64_mca_init(void) ia64_log_init(SAL_INFO_TYPE_INIT); ia64_log_init(SAL_INFO_TYPE_CMC); ia64_log_init(SAL_INFO_TYPE_CPE); -#endif /* !XEN */ + +#ifdef XEN + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_MCA]); + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_INIT]); + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_CMC]); + INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_CPE]); + + open_softirq(CMC_DISABLE_SOFTIRQ, + (softirq_handler)ia64_mca_cmc_vector_disable); + open_softirq(CMC_ENABLE_SOFTIRQ, + (softirq_handler)ia64_mca_cmc_vector_enable); + + for (i = 0; i < IA64_MAX_LOG_TYPES; i++) + ia64_log_queue(i, 0); +#endif mca_init = 1; printk(KERN_INFO "MCA related initialization done\n"); } -#ifndef XEN /* * ia64_mca_late_init * @@ -1555,20 +1828,34 @@ ia64_mca_late_init(void) return 0; /* Setup the CMCI/P vector and handler */ +#ifndef XEN init_timer(&cmc_poll_timer); cmc_poll_timer.function = ia64_mca_cmc_poll; +#else + init_timer(&cmc_poll_timer, ia64_mca_cmc_poll, NULL, smp_processor_id()); + printk("INIT_TIMER(cmc_poll_timer): on cpu%d\n", smp_processor_id()); +#endif /* Unmask/enable the vector */ cmc_polling_enabled = 0; +#ifndef XEN /* XXX FIXME */ schedule_work(&cmc_enable_work); +#else + cpumask_raise_softirq(cpu_online_map, CMC_ENABLE_SOFTIRQ); +#endif IA64_MCA_DEBUG("%s: CMCI/P setup and enabled.\n", __FUNCTION__); #ifdef CONFIG_ACPI /* Setup the CPEI/P vector and handler */ cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); +#ifndef XEN init_timer(&cpe_poll_timer); cpe_poll_timer.function = ia64_mca_cpe_poll; +#else + init_timer(&cpe_poll_timer, ia64_mca_cpe_poll, NULL, smp_processor_id()); + printk("INIT_TIMER(cpe_poll_timer): on cpu%d\n", smp_processor_id()); +#endif { irq_desc_t *desc; @@ -1598,5 +1885,8 @@ ia64_mca_late_init(void) return 0; } +#ifndef XEN device_initcall(ia64_mca_late_init); -#endif /* !XEN */ +#else +__initcall(ia64_mca_late_init); +#endif From b83c6a48ae98f194ac6042e7072ac220e0b674ba Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:10 -0700 Subject: [PATCH 002/282] [IA64] MCA support - interrupt.h changes for MCA support Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/include/asm-ia64/linux-xen/linux/interrupt.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xen/include/asm-ia64/linux-xen/linux/interrupt.h b/xen/include/asm-ia64/linux-xen/linux/interrupt.h index a58afbec08..d6bbeb7772 100644 --- a/xen/include/asm-ia64/linux-xen/linux/interrupt.h +++ b/xen/include/asm-ia64/linux-xen/linux/interrupt.h @@ -29,13 +29,15 @@ */ #ifdef XEN typedef void irqreturn_t; +#define IRQ_NONE +#define IRQ_HANDLED +#define IRQ_RETVAL(x) #else typedef int irqreturn_t; -#endif - #define IRQ_NONE (0) #define IRQ_HANDLED (1) #define IRQ_RETVAL(x) ((x) != 0) +#endif #ifndef XEN struct irqaction { From 849a524a96b4ce54ae8ff0ef72b5b13798dbf617 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:11 -0700 Subject: [PATCH 003/282] [IA64] MCA support - Add percpu data physical addr mca_asm.S Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/linux-xen/mca_asm.S | 152 ++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 10 deletions(-) diff --git a/xen/arch/ia64/linux-xen/mca_asm.S b/xen/arch/ia64/linux-xen/mca_asm.S index 1f1cb4dda8..a73a8e1daa 100644 --- a/xen/arch/ia64/linux-xen/mca_asm.S +++ b/xen/arch/ia64/linux-xen/mca_asm.S @@ -24,6 +24,9 @@ #include #include #include +#ifdef XEN +#include +#endif /* * When we get a machine check, the kernel stack pointer is no longer @@ -50,8 +53,7 @@ */ #ifdef XEN #define SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(_tmp) \ - movl _tmp=THIS_CPU(ia64_sal_to_os_handoff_state_addr);; \ - tpa _tmp=_tmp;; \ + GET_THIS_PADDR(_tmp, ia64_sal_to_os_handoff_state_addr);; \ ld8 _tmp=[_tmp];; \ st8 [_tmp]=r1,0x08;; \ st8 [_tmp]=r8,0x08;; \ @@ -72,6 +74,7 @@ st8 [_tmp]=r12,0x08;; \ st8 [_tmp]=r17,0x08;; \ st8 [_tmp]=r18,0x08 +#endif /* XEN */ /* * OS_MCA_TO_SAL_HANDOFF_STATE (SAL 3.0 spec) @@ -101,6 +104,24 @@ * imots_sal_check_ra=Return address to location within SAL_CHECK * */ +#ifdef XEN +#define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\ + movl tmp=IA64_MCA_COLD_BOOT; \ + GET_THIS_PADDR(r2,ia64_sal_to_os_handoff_state_addr);; \ + ld8 sal_to_os_handoff=[sal_to_os_handoff];; \ + movl os_to_sal_handoff=ia64_os_to_sal_handoff_state;; \ + dep os_to_sal_handoff = 0, os_to_sal_handoff, 60, 4;; \ + /*DATA_VA_TO_PA(os_to_sal_handoff);;*/ \ + st8 [os_to_sal_handoff]=tmp,8;; \ + ld8 tmp=[sal_to_os_handoff],48;; \ + st8 [os_to_sal_handoff]=tmp,8;; \ + movl tmp=IA64_MCA_SAME_CONTEXT;; \ + st8 [os_to_sal_handoff]=tmp,8;; \ + ld8 tmp=[sal_to_os_handoff],-8;; \ + st8 [os_to_sal_handoff]=tmp,8;; \ + ld8 tmp=[sal_to_os_handoff];; \ + st8 [os_to_sal_handoff]=tmp;; +#else /* XEN */ #define COLD_BOOT_HANDOFF_STATE(sal_to_os_handoff,os_to_sal_handoff,tmp)\ movl tmp=IA64_MCA_COLD_BOOT; \ movl sal_to_os_handoff=__pa(ia64_sal_to_os_handoff_state); \ @@ -114,13 +135,13 @@ st8 [os_to_sal_handoff]=tmp,8;; \ ld8 tmp=[sal_to_os_handoff];; \ st8 [os_to_sal_handoff]=tmp;; +#endif /* XEN */ #define GET_IA64_MCA_DATA(reg) \ GET_THIS_PADDR(reg, ia64_mca_data) \ ;; \ ld8 reg=[reg] -#endif /* XEN */ .global ia64_os_mca_dispatch .global ia64_os_mca_dispatch_end #ifndef XEN @@ -132,7 +153,40 @@ .text .align 16 -#ifndef XEN +#ifdef XEN +/* + * void set_per_cpu_data(void) + * { + * int i; + * for (i = 0; i < 64; i++) { + * if (ia64_mca_tlb_list[i].cr_lid == ia64_getreg(_IA64_REG_CR_LID)) { + * ia64_set_kr(IA64_KR_PER_CPU_DATA, ia64_mca_tlb_list[i].percpu_paddr); + * return; + * } + * } + * while(1); // Endless loop on error + * } + */ +#define SET_PER_CPU_DATA() \ + LOAD_PHYSICAL(p0,r2,ia64_mca_tlb_list);; \ + mov r7 = r0; \ + mov r6 = r0;; \ + adds r3 = IA64_MCA_PERCPU_OFFSET, r2; \ +1: add r4 = r6, r2; \ + mov r5=cr.lid;; \ + adds r7 = 1, r7; \ + ld8 r4 = [r4];; \ + cmp.ne p6, p7 = r5, r4; \ + cmp4.lt p8, p9 = NR_CPUS-1, r7; \ +(p7) br.cond.dpnt 3f; \ + adds r6 = 16, r6; \ +(p9) br.cond.sptk 1b; \ +2: br 2b;; /* Endless loop on error */ \ +3: add r4 = r6, r3;; \ + ld8 r4 = [r4];; \ + mov ar.k3=r4 +#endif /* XEN */ + /* * Just the TLB purge part is moved to a separate function * so we can re-use the code for cpu hotplug code as well @@ -221,6 +275,44 @@ ia64_do_tlb_purge: ;; srlz.i ;; +#ifdef XEN + // 5. VHPT +#if VHPT_ENABLED + // r25 = __va_ul(vcpu_vhpt_maddr(v)); + GET_THIS_PADDR(r2,cpu_kr);; + add r2=IA64_KR_CURRENT_OFFSET,r2;; + ld8 r2=[r2];; +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT +#define HAS_PERVCPU_VHPT_MASK 0x2 + dep r3=0,r2,60,4;; // virtual to physical + add r3=IA64_VCPU_DOMAIN_OFFSET,r3;; + ld8 r3=[r3];; + dep r3=0,r3,60,4;; // virtual to physical + add r3=IA64_DOMAIN_FLAGS_OFFSET,r3;; + ld8 r3=[r3];; + and r3=HAS_PERVCPU_VHPT_MASK,r3;; + cmp.eq p6,p0=r3,r0;; +(p6) br.cond.sptk .not_pervcpu_vhpt + add r2=IA64_VCPU_VHPT_MADDR_OFFSET,r2;; + dep r2=0,r2,60,4;; // virtual to physical + ld8 r2=[r2];; + dep r25=-1,r2,60,4;; // physical to virtual + br.sptk .percpu_vhpt_done +#endif +.not_pervcpu_vhpt: + GET_THIS_PADDR(r2, vhpt_paddr);; + ld8 r2=[r2];; + dep r25=-1,r2,60,4;; // physical to virtual +.percpu_vhpt_done: + dep r20=0,r25,0,IA64_GRANULE_SHIFT + mov r24=IA64_GRANULE_SHIFT<<2 + ;; + ptr.d r20,r24 + ;; + srlz.d + ;; +#endif +#endif // Now branch away to caller. br.sptk.many b1 ;; @@ -235,6 +327,9 @@ ia64_os_mca_spin: cmp.ne p6,p0=r4,r0 (p6) br ia64_os_mca_spin +#ifdef XEN + SET_PER_CPU_DATA();; +#endif // Save the SAL to OS MCA handoff state as defined // by SAL SPEC 3.0 // NOTE : The order in which the state gets saved @@ -250,7 +345,19 @@ begin_os_mca_dump: ia64_os_mca_done_dump: +#ifdef XEN + // Set current to ar.k6 + GET_THIS_PADDR(r2,cpu_kr);; + add r2=IA64_KR_CURRENT_OFFSET,r2;; + ld8 r2=[r2];; + mov ar.k6=r2;; + + GET_THIS_PADDR(r2,ia64_sal_to_os_handoff_state_addr);; + ld8 r2=[r2];; + adds r16=56,r2 +#else LOAD_PHYSICAL(p0,r16,ia64_sal_to_os_handoff_state+56) +#endif ;; ld8 r18=[r16] // Get processor state parameter on existing PALE_CHECK. ;; @@ -342,6 +449,28 @@ ia64_reload_tr: ;; srlz.d ;; +#ifdef XEN + // 5. VHPT +#if VHPT_ENABLED + // r25 = __va_ul(vcpu_vhpt_maddr(v)); + dep r20=0,r25,0,IA64_GRANULE_SHIFT + movl r26=PAGE_KERNEL + ;; + mov r21=IA64_TR_VHPT + dep r22=0,r20,60,4 // physical address of + // va_vhpt & ~(IA64_GRANULE_SIZE - 1) + mov r24=IA64_GRANULE_SHIFT<<2 + ;; + or r23=r22,r26 // construct PA | page properties + mov cr.itir=r24 + mov cr.ifa=r20 + ;; + itr.d dtr[r21]=r23 // wire in new mapping... + ;; + srlz.d + ;; +#endif +#endif br.sptk.many done_tlb_purge_and_reload err: COLD_BOOT_HANDOFF_STATE(r20,r21,r22) @@ -874,12 +1003,6 @@ end_os_mca_restore: br ia64_os_mca_done_restore;; //EndStub////////////////////////////////////////////////////////////////////// -#else -ia64_os_mca_dispatch: -1: - br.sptk 1b -ia64_os_mca_dispatch_end: -#endif /* !XEN */ // ok, the issue here is that we need to save state information so @@ -911,6 +1034,15 @@ ia64_os_mca_dispatch_end: GLOBAL_ENTRY(ia64_monarch_init_handler) .prologue +#ifdef XEN /* Need in ia64_monarch_init_handler? */ + SET_PER_CPU_DATA();; + + // Set current to ar.k6 + GET_THIS_PADDR(r2,cpu_kr);; + add r2=IA64_KR_CURRENT_OFFSET,r2;; + ld8 r2=[r2];; + mov ar.k6=r2;; +#endif // stash the information the SAL passed to os SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2) ;; From cbc0fb77f39a9b7ecc22c1e84421433a571bf560 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:12 -0700 Subject: [PATCH 004/282] [IA64] MCA support - Fix GET_THIS_PADDR and define log queue struct Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/include/asm-ia64/linux-xen/asm/mca_asm.h | 4 +-- xen/include/asm-ia64/xenmca.h | 34 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 xen/include/asm-ia64/xenmca.h diff --git a/xen/include/asm-ia64/linux-xen/asm/mca_asm.h b/xen/include/asm-ia64/linux-xen/asm/mca_asm.h index 3cf3c38919..01c278afc2 100644 --- a/xen/include/asm-ia64/linux-xen/asm/mca_asm.h +++ b/xen/include/asm-ia64/linux-xen/asm/mca_asm.h @@ -59,8 +59,8 @@ #ifdef XEN #define GET_THIS_PADDR(reg, var) \ - movl reg = THIS_CPU(var) \ - tpa reg = reg + mov reg = IA64_KR(PER_CPU_DATA);; \ + addl reg = THIS_CPU(var) - PERCPU_ADDR, reg #else #define GET_THIS_PADDR(reg, var) \ mov reg = IA64_KR(PER_CPU_DATA);; \ diff --git a/xen/include/asm-ia64/xenmca.h b/xen/include/asm-ia64/xenmca.h new file mode 100644 index 0000000000..c541b237be --- /dev/null +++ b/xen/include/asm-ia64/xenmca.h @@ -0,0 +1,34 @@ +/* + * File: xenmca.h + * Purpose: Machine check handling specific defines for Xen + * + * Copyright (C) 2006 FUJITSU LTD. (kaz@jp.fujitsu.com) + */ + +#ifndef _ASM_IA64_XENMCA_H +#define _ASM_IA64_XENMCA_H + +#ifndef __ASSEMBLER__ +#include +#include + +typedef struct sal_queue_entry_t { + int cpuid; + int sal_info_type; + unsigned int vector; + unsigned int virq; + unsigned int length; + struct list_head list; +} sal_queue_entry_t; + +extern struct list_head sal_queue[]; + +struct ia64_mca_tlb_info { + u64 cr_lid; + u64 percpu_paddr; +}; + +extern struct ia64_mca_tlb_info ia64_mca_tlb_list[]; +#endif /* __ASSEMBLER__ */ + +#endif /* _ASM_IA64_XENMCA_H */ From 3614e3523b9f689665b3b701d25792a332e44e8e Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:14 -0700 Subject: [PATCH 005/282] [IA64] MCA support - Add binding of virq/ipi to irq Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- .../arch/ia64/kernel/irq_ia64.c | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c index 49b6f8fe57..c5bba01228 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c @@ -241,9 +241,15 @@ static struct irqaction ipi_irqaction = { static DEFINE_PER_CPU(int, timer_irq) = -1; static DEFINE_PER_CPU(int, ipi_irq) = -1; static DEFINE_PER_CPU(int, resched_irq) = -1; +static DEFINE_PER_CPU(int, cmc_irq) = -1; +static DEFINE_PER_CPU(int, cmcp_irq) = -1; +static DEFINE_PER_CPU(int, cpep_irq) = -1; static char timer_name[NR_CPUS][15]; static char ipi_name[NR_CPUS][15]; static char resched_name[NR_CPUS][15]; +static char cmc_name[NR_CPUS][15]; +static char cmcp_name[NR_CPUS][15]; +static char cpep_name[NR_CPUS][15]; struct saved_irq { unsigned int irq; @@ -323,6 +329,43 @@ xen_register_percpu_irq (unsigned int irq, struct irqaction *action, int save) break; case IA64_SPURIOUS_INT_VECTOR: break; + case IA64_CMC_VECTOR: + sprintf(cmc_name[cpu], "%s%d", action->name, cpu); + ret = bind_virq_to_irqhandler(VIRQ_MCA_CMC, cpu, + action->handler, + action->flags, + cmc_name[cpu], + action->dev_id); + per_cpu(cmc_irq,cpu) = ret; + printk(KERN_INFO "register VIRQ_MCA_CMC (%s) to xen " + "irq (%d)\n", cmc_name[cpu], ret); + break; + case IA64_CMCP_VECTOR: + sprintf(cmcp_name[cpu], "%s%d", action->name, cpu); + ret = bind_ipi_to_irqhandler(CMCP_VECTOR, cpu, + action->handler, + action->flags, + cmcp_name[cpu], + action->dev_id); + per_cpu(cmcp_irq,cpu) = ret; + printk(KERN_INFO "register CMCP_VECTOR (%s) to xen " + "irq (%d)\n", cmcp_name[cpu], ret); + break; + case IA64_CPEP_VECTOR: + sprintf(cpep_name[cpu], "%s%d", action->name, cpu); + ret = bind_ipi_to_irqhandler(CPEP_VECTOR, cpu, + action->handler, + action->flags, + cpep_name[cpu], + action->dev_id); + per_cpu(cpep_irq,cpu) = ret; + printk(KERN_INFO "register CPEP_VECTOR (%s) to xen " + "irq (%d)\n", cpep_name[cpu], ret); + break; + case IA64_CPE_VECTOR: + printk(KERN_WARNING "register IA64_CPE_VECTOR " + "IGNORED\n"); + break; default: printk(KERN_WARNING "Percpu irq %d is unsupported by xen!\n", irq); break; @@ -373,6 +416,18 @@ unbind_evtchn_callback(struct notifier_block *nfb, if (action == CPU_DEAD) { /* Unregister evtchn. */ + if (per_cpu(cpep_irq,cpu) >= 0) { + unbind_from_irqhandler(per_cpu(cpep_irq, cpu), NULL); + per_cpu(cpep_irq, cpu) = -1; + } + if (per_cpu(cmcp_irq,cpu) >= 0) { + unbind_from_irqhandler(per_cpu(cmcp_irq, cpu), NULL); + per_cpu(cmcp_irq, cpu) = -1; + } + if (per_cpu(cmc_irq,cpu) >= 0) { + unbind_from_irqhandler(per_cpu(cmc_irq, cpu), NULL); + per_cpu(cmc_irq, cpu) = -1; + } if (per_cpu(ipi_irq,cpu) >= 0) { unbind_from_irqhandler (per_cpu(ipi_irq, cpu), NULL); per_cpu(ipi_irq, cpu) = -1; @@ -503,6 +558,12 @@ ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect) case IA64_IPI_RESCHEDULE: irq = per_cpu(ipi_to_irq, cpu)[RESCHEDULE_VECTOR]; break; + case IA64_CMCP_VECTOR: + irq = per_cpu(ipi_to_irq, cpu)[CMCP_VECTOR]; + break; + case IA64_CPEP_VECTOR: + irq = per_cpu(ipi_to_irq, cpu)[CPEP_VECTOR]; + break; default: printk(KERN_WARNING"Unsupported IPI type 0x%x\n", vector); irq = 0; From 1f108dbd81d4f5970928aa6d51b1c686fc984bd8 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:15 -0700 Subject: [PATCH 006/282] [IA64] MCA support - Define MCA interrupt vector Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- linux-2.6-xen-sparse/include/asm-ia64/irq.h | 4 +++- xen/include/asm-ia64/event.h | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/include/asm-ia64/irq.h b/linux-2.6-xen-sparse/include/asm-ia64/irq.h index a86f83b9f3..dbe0a2e2b8 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/irq.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/irq.h @@ -42,7 +42,9 @@ #define RESCHEDULE_VECTOR 0 #define IPI_VECTOR 1 -#define NR_IPIS 2 +#define CMCP_VECTOR 2 +#define CPEP_VECTOR 3 +#define NR_IPIS 4 #endif /* CONFIG_XEN */ /* diff --git a/xen/include/asm-ia64/event.h b/xen/include/asm-ia64/event.h index ef4c33f2be..c3d67cfa2c 100644 --- a/xen/include/asm-ia64/event.h +++ b/xen/include/asm-ia64/event.h @@ -70,6 +70,8 @@ static inline int arch_virq_is_global(int virq) switch ( virq ) { case VIRQ_ITC: + case VIRQ_MCA_CMC: + case VIRQ_MCA_CPE: rc = 0; break; default: From 3092011efc951319517ef2d11a19170fbe6c6d33 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:16 -0700 Subject: [PATCH 007/282] [IA64] MCA support - Add sal emulation Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/xen/fw_emul.c | 238 ++++++++++++++++++++++++++++++++++-- 1 file changed, 228 insertions(+), 10 deletions(-) diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c index 6c9eb054f4..ff024147a8 100644 --- a/xen/arch/ia64/xen/fw_emul.c +++ b/xen/arch/ia64/xen/fw_emul.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "hpsim_ssc.h" @@ -34,6 +35,93 @@ extern unsigned long running_on_sim; +struct sal_mc_params { + u64 param_type; + u64 i_or_m; + u64 i_or_m_val; + u64 timeout; + u64 rz_always; +} sal_mc_params[SAL_MC_PARAM_CPE_INT + 1]; + +struct sal_vectors { + u64 vector_type; + u64 handler_addr1; + u64 gp1; + u64 handler_len1; + u64 handler_addr2; + u64 gp2; + u64 handler_len2; +} sal_vectors[SAL_VECTOR_OS_BOOT_RENDEZ + 1]; + +struct smp_call_args_t { + u64 type; + u64 ret; + u64 target; + struct domain *domain; + int corrected; + int status; + void *data; +}; + +extern sal_log_record_header_t *sal_record; +DEFINE_SPINLOCK(sal_record_lock); + +extern spinlock_t sal_queue_lock; + +#define IA64_SAL_NO_INFORMATION_AVAILABLE -5 + +#if defined(IA64_SAL_DEBUG_INFO) +static const char * const rec_name[] = { "MCA", "INIT", "CMC", "CPE" }; + +# define IA64_SAL_DEBUG(fmt...) printk("sal_emulator: " fmt) +#else +# define IA64_SAL_DEBUG(fmt...) +#endif + +void get_state_info_on(void *data) { + struct smp_call_args_t *arg = data; + int flags; + + spin_lock_irqsave(&sal_record_lock, flags); + memset(sal_record, 0, ia64_sal_get_state_info_size(arg->type)); + arg->ret = ia64_sal_get_state_info(arg->type, (u64 *)sal_record); + IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) on CPU#%d returns %ld.\n", + rec_name[arg->type], smp_processor_id(), arg->ret); + if (arg->corrected) { + sal_record->severity = sal_log_severity_corrected; + IA64_SAL_DEBUG("%s: IA64_SAL_CLEAR_STATE_INFO(SAL_INFO_TYPE_MCA)" + " force\n", __FUNCTION__); + } + if (arg->ret > 0) { + /* + * Save current->domain and set to local(caller) domain for + * xencomm_paddr_to_maddr() which calculates maddr from + * paddr using mpa value of current->domain. + */ + struct domain *save; + save = current->domain; + current->domain = arg->domain; + if (xencomm_copy_to_guest((void*)arg->target, + sal_record, arg->ret, 0)) { + printk("SAL_GET_STATE_INFO can't copy to user!!!!\n"); + arg->status = IA64_SAL_NO_INFORMATION_AVAILABLE; + arg->ret = 0; + } + /* Restore current->domain to saved value. */ + current->domain = save; + } + spin_unlock_irqrestore(&sal_record_lock, flags); +} + +void clear_state_info_on(void *data) { + struct smp_call_args_t *arg = data; + + arg->ret = ia64_sal_clear_state_info(arg->type); + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) on CPU#%d returns %ld.\n", + rec_name[arg->type], smp_processor_id(), arg->ret); + +} + struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, @@ -104,27 +192,157 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, } } else - printk("*** CALLED SAL_SET_VECTORS %lu. IGNORED...\n", - in1); + { + if (in1 > sizeof(sal_vectors)/sizeof(sal_vectors[0])-1) + BUG(); + sal_vectors[in1].vector_type = in1; + sal_vectors[in1].handler_addr1 = in2; + sal_vectors[in1].gp1 = in3; + sal_vectors[in1].handler_len1 = in4; + sal_vectors[in1].handler_addr2 = in5; + sal_vectors[in1].gp2 = in6; + sal_vectors[in1].handler_len2 = in7; + } break; case SAL_GET_STATE_INFO: - /* No more info. */ - status = -5; - r9 = 0; + { + sal_queue_entry_t *e; + unsigned long flags; + struct smp_call_args_t arg; + + spin_lock_irqsave(&sal_queue_lock, flags); + if (list_empty(&sal_queue[in1])) { + sal_log_record_header_t header; + XEN_GUEST_HANDLE(void) handle = + *(XEN_GUEST_HANDLE(void)*)&in3; + + IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s) " + "no sal_queue entry found.\n", + rec_name[in1]); + memset(&header, 0, sizeof(header)); + + if (copy_to_guest(handle, &header, 1)) { + printk("sal_emulator: " + "SAL_GET_STATE_INFO can't copy " + "empty header to user: 0x%lx\n", + in3); + } + status = IA64_SAL_NO_INFORMATION_AVAILABLE; + r9 = 0; + spin_unlock_irqrestore(&sal_queue_lock, flags); + break; + } + e = list_entry(sal_queue[in1].next, + sal_queue_entry_t, list); + spin_unlock_irqrestore(&sal_queue_lock, flags); + + IA64_SAL_DEBUG("SAL_GET_STATE_INFO(%s <= %s) " + "on CPU#%d.\n", + rec_name[e->sal_info_type], + rec_name[in1], e->cpuid); + + arg.type = e->sal_info_type; + arg.target = in3; + arg.corrected = !!((in1 != e->sal_info_type) && + (e->sal_info_type == SAL_INFO_TYPE_MCA)); + arg.domain = current->domain; + arg.status = 0; + + if (e->cpuid == smp_processor_id()) { + IA64_SAL_DEBUG("SAL_GET_STATE_INFO: local\n"); + get_state_info_on(&arg); + } else { + int ret; + IA64_SAL_DEBUG("SAL_GET_STATE_INFO: remote\n"); + ret = smp_call_function_single(e->cpuid, + get_state_info_on, + &arg, 0, 1); + if (ret < 0) { + printk("SAL_GET_STATE_INFO " + "smp_call_function_single error:" + " %d\n", ret); + arg.ret = 0; + arg.status = + IA64_SAL_NO_INFORMATION_AVAILABLE; + } + } + r9 = arg.ret; + status = arg.status; + if (r9 == 0) { + spin_lock_irqsave(&sal_queue_lock, flags); + list_del(&e->list); + spin_unlock_irqrestore(&sal_queue_lock, flags); + xfree(e); + } + } break; case SAL_GET_STATE_INFO_SIZE: - /* Return a dummy size. */ - status = 0; - r9 = 128; + r9 = ia64_sal_get_state_info_size(in1); break; case SAL_CLEAR_STATE_INFO: - /* Noop. */ + { + sal_queue_entry_t *e; + unsigned long flags; + struct smp_call_args_t arg; + + spin_lock_irqsave(&sal_queue_lock, flags); + if (list_empty(&sal_queue[in1])) { + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s) " + "no sal_queue entry found.\n", + rec_name[in1]); + status = IA64_SAL_NO_INFORMATION_AVAILABLE; + r9 = 0; + spin_unlock_irqrestore(&sal_queue_lock, flags); + break; + } + e = list_entry(sal_queue[in1].next, + sal_queue_entry_t, list); + + list_del(&e->list); + spin_unlock_irqrestore(&sal_queue_lock, flags); + + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO(%s <= %s) " + "on CPU#%d.\n", + rec_name[e->sal_info_type], + rec_name[in1], e->cpuid); + + + arg.type = e->sal_info_type; + arg.status = 0; + if (e->cpuid == smp_processor_id()) { + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO: local\n"); + clear_state_info_on(&arg); + } else { + int ret; + IA64_SAL_DEBUG("SAL_CLEAR_STATE_INFO: remote\n"); + ret = smp_call_function_single(e->cpuid, + clear_state_info_on, &arg, 0, 1); + if (ret < 0) { + printk("sal_emulator: " + "SAL_CLEAR_STATE_INFO " + "smp_call_function_single error:" + " %d\n", ret); + arg.ret = 0; + arg.status = + IA64_SAL_NO_INFORMATION_AVAILABLE; + } + } + r9 = arg.ret; + status = arg.status; + xfree(e); + } break; case SAL_MC_RENDEZ: printk("*** CALLED SAL_MC_RENDEZ. IGNORED...\n"); break; case SAL_MC_SET_PARAMS: - printk("*** CALLED SAL_MC_SET_PARAMS. IGNORED...\n"); + if (in1 > sizeof(sal_mc_params)/sizeof(sal_mc_params[0])) + BUG(); + sal_mc_params[in1].param_type = in1; + sal_mc_params[in1].i_or_m = in2; + sal_mc_params[in1].i_or_m_val = in3; + sal_mc_params[in1].timeout = in4; + sal_mc_params[in1].rz_always = in5; break; case SAL_CACHE_FLUSH: if (1) { From 61337dd1acd8a2d5d2e10cb715df0c8dfda0e9a8 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:17 -0700 Subject: [PATCH 008/282] [IA64] MCA support - add include/asm-ia64/sal.h to sparse tree Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- linux-2.6-xen-sparse/include/asm-ia64/sal.h | 883 ++++++++++++++++++++ 1 file changed, 883 insertions(+) create mode 100644 linux-2.6-xen-sparse/include/asm-ia64/sal.h diff --git a/linux-2.6-xen-sparse/include/asm-ia64/sal.h b/linux-2.6-xen-sparse/include/asm-ia64/sal.h new file mode 100644 index 0000000000..0b210abbe0 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-ia64/sal.h @@ -0,0 +1,883 @@ +#ifndef _ASM_IA64_SAL_H +#define _ASM_IA64_SAL_H + +/* + * System Abstraction Layer definitions. + * + * This is based on version 2.5 of the manual "IA-64 System + * Abstraction Layer". + * + * Copyright (C) 2001 Intel + * Copyright (C) 2002 Jenna Hall + * Copyright (C) 2001 Fred Lewis + * Copyright (C) 1998, 1999, 2001, 2003 Hewlett-Packard Co + * David Mosberger-Tang + * Copyright (C) 1999 Srinivasa Prasad Thirumalachar + * + * 02/01/04 J. Hall Updated Error Record Structures to conform to July 2001 + * revision of the SAL spec. + * 01/01/03 fvlewis Updated Error Record Structures to conform with Nov. 2000 + * revision of the SAL spec. + * 99/09/29 davidm Updated for SAL 2.6. + * 00/03/29 cfleck Updated SAL Error Logging info for processor (SAL 2.6) + * (plus examples of platform error info structures from smariset @ Intel) + */ + +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT 0 +#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT 1 +#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT 2 +#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT 3 + +#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1< +#include +#include + +#include +#include +#include + +extern spinlock_t sal_lock; + +/* SAL spec _requires_ eight args for each call. */ +#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7) \ + result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7) + +# define SAL_CALL(result,args...) do { \ + unsigned long __ia64_sc_flags; \ + struct ia64_fpreg __ia64_sc_fr[6]; \ + ia64_save_scratch_fpregs(__ia64_sc_fr); \ + spin_lock_irqsave(&sal_lock, __ia64_sc_flags); \ + __SAL_CALL(result, args); \ + spin_unlock_irqrestore(&sal_lock, __ia64_sc_flags); \ + ia64_load_scratch_fpregs(__ia64_sc_fr); \ +} while (0) + +# define SAL_CALL_NOLOCK(result,args...) do { \ + unsigned long __ia64_scn_flags; \ + struct ia64_fpreg __ia64_scn_fr[6]; \ + ia64_save_scratch_fpregs(__ia64_scn_fr); \ + local_irq_save(__ia64_scn_flags); \ + __SAL_CALL(result, args); \ + local_irq_restore(__ia64_scn_flags); \ + ia64_load_scratch_fpregs(__ia64_scn_fr); \ +} while (0) + +# define SAL_CALL_REENTRANT(result,args...) do { \ + struct ia64_fpreg __ia64_scs_fr[6]; \ + ia64_save_scratch_fpregs(__ia64_scs_fr); \ + preempt_disable(); \ + __SAL_CALL(result, args); \ + preempt_enable(); \ + ia64_load_scratch_fpregs(__ia64_scs_fr); \ +} while (0) + +#define SAL_SET_VECTORS 0x01000000 +#define SAL_GET_STATE_INFO 0x01000001 +#define SAL_GET_STATE_INFO_SIZE 0x01000002 +#define SAL_CLEAR_STATE_INFO 0x01000003 +#define SAL_MC_RENDEZ 0x01000004 +#define SAL_MC_SET_PARAMS 0x01000005 +#define SAL_REGISTER_PHYSICAL_ADDR 0x01000006 + +#define SAL_CACHE_FLUSH 0x01000008 +#define SAL_CACHE_INIT 0x01000009 +#define SAL_PCI_CONFIG_READ 0x01000010 +#define SAL_PCI_CONFIG_WRITE 0x01000011 +#define SAL_FREQ_BASE 0x01000012 +#define SAL_PHYSICAL_ID_INFO 0x01000013 + +#define SAL_UPDATE_PAL 0x01000020 + +struct ia64_sal_retval { + /* + * A zero status value indicates call completed without error. + * A negative status value indicates reason of call failure. + * A positive status value indicates success but an + * informational value should be printed (e.g., "reboot for + * change to take effect"). + */ + s64 status; + u64 v0; + u64 v1; + u64 v2; +}; + +typedef struct ia64_sal_retval (*ia64_sal_handler) (u64, ...); + +enum { + SAL_FREQ_BASE_PLATFORM = 0, + SAL_FREQ_BASE_INTERVAL_TIMER = 1, + SAL_FREQ_BASE_REALTIME_CLOCK = 2 +}; + +/* + * The SAL system table is followed by a variable number of variable + * length descriptors. The structure of these descriptors follows + * below. + * The defininition follows SAL specs from July 2000 + */ +struct ia64_sal_systab { + u8 signature[4]; /* should be "SST_" */ + u32 size; /* size of this table in bytes */ + u8 sal_rev_minor; + u8 sal_rev_major; + u16 entry_count; /* # of entries in variable portion */ + u8 checksum; + u8 reserved1[7]; + u8 sal_a_rev_minor; + u8 sal_a_rev_major; + u8 sal_b_rev_minor; + u8 sal_b_rev_major; + /* oem_id & product_id: terminating NUL is missing if string is exactly 32 bytes long. */ + u8 oem_id[32]; + u8 product_id[32]; /* ASCII product id */ + u8 reserved2[8]; +}; + +enum sal_systab_entry_type { + SAL_DESC_ENTRY_POINT = 0, + SAL_DESC_MEMORY = 1, + SAL_DESC_PLATFORM_FEATURE = 2, + SAL_DESC_TR = 3, + SAL_DESC_PTC = 4, + SAL_DESC_AP_WAKEUP = 5 +}; + +/* + * Entry type: Size: + * 0 48 + * 1 32 + * 2 16 + * 3 32 + * 4 16 + * 5 16 + */ +#define SAL_DESC_SIZE(type) "\060\040\020\040\020\020"[(unsigned) type] + +typedef struct ia64_sal_desc_entry_point { + u8 type; + u8 reserved1[7]; + u64 pal_proc; + u64 sal_proc; + u64 gp; + u8 reserved2[16]; +}ia64_sal_desc_entry_point_t; + +typedef struct ia64_sal_desc_memory { + u8 type; + u8 used_by_sal; /* needs to be mapped for SAL? */ + u8 mem_attr; /* current memory attribute setting */ + u8 access_rights; /* access rights set up by SAL */ + u8 mem_attr_mask; /* mask of supported memory attributes */ + u8 reserved1; + u8 mem_type; /* memory type */ + u8 mem_usage; /* memory usage */ + u64 addr; /* physical address of memory */ + u32 length; /* length (multiple of 4KB pages) */ + u32 reserved2; + u8 oem_reserved[8]; +} ia64_sal_desc_memory_t; + +typedef struct ia64_sal_desc_platform_feature { + u8 type; + u8 feature_mask; + u8 reserved1[14]; +} ia64_sal_desc_platform_feature_t; + +typedef struct ia64_sal_desc_tr { + u8 type; + u8 tr_type; /* 0 == instruction, 1 == data */ + u8 regnum; /* translation register number */ + u8 reserved1[5]; + u64 addr; /* virtual address of area covered */ + u64 page_size; /* encoded page size */ + u8 reserved2[8]; +} ia64_sal_desc_tr_t; + +typedef struct ia64_sal_desc_ptc { + u8 type; + u8 reserved1[3]; + u32 num_domains; /* # of coherence domains */ + u64 domain_info; /* physical address of domain info table */ +} ia64_sal_desc_ptc_t; + +typedef struct ia64_sal_ptc_domain_info { + u64 proc_count; /* number of processors in domain */ + u64 proc_list; /* physical address of LID array */ +} ia64_sal_ptc_domain_info_t; + +typedef struct ia64_sal_ptc_domain_proc_entry { + u64 id : 8; /* id of processor */ + u64 eid : 8; /* eid of processor */ +} ia64_sal_ptc_domain_proc_entry_t; + + +#define IA64_SAL_AP_EXTERNAL_INT 0 + +typedef struct ia64_sal_desc_ap_wakeup { + u8 type; + u8 mechanism; /* 0 == external interrupt */ + u8 reserved1[6]; + u64 vector; /* interrupt vector in range 0x10-0xff */ +} ia64_sal_desc_ap_wakeup_t ; + +extern ia64_sal_handler ia64_sal; +extern struct ia64_sal_desc_ptc *ia64_ptc_domain_info; + +extern unsigned short sal_revision; /* supported SAL spec revision */ +extern unsigned short sal_version; /* SAL version; OEM dependent */ +#define SAL_VERSION_CODE(major, minor) ((BIN2BCD(major) << 8) | BIN2BCD(minor)) + +extern const char *ia64_sal_strerror (long status); +extern void ia64_sal_init (struct ia64_sal_systab *sal_systab); + +/* SAL information type encodings */ +enum { + SAL_INFO_TYPE_MCA = 0, /* Machine check abort information */ + SAL_INFO_TYPE_INIT = 1, /* Init information */ + SAL_INFO_TYPE_CMC = 2, /* Corrected machine check information */ + SAL_INFO_TYPE_CPE = 3 /* Corrected platform error information */ +}; + +/* Encodings for machine check parameter types */ +enum { + SAL_MC_PARAM_RENDEZ_INT = 1, /* Rendezvous interrupt */ + SAL_MC_PARAM_RENDEZ_WAKEUP = 2, /* Wakeup */ + SAL_MC_PARAM_CPE_INT = 3 /* Corrected Platform Error Int */ +}; + +/* Encodings for rendezvous mechanisms */ +enum { + SAL_MC_PARAM_MECHANISM_INT = 1, /* Use interrupt */ + SAL_MC_PARAM_MECHANISM_MEM = 2 /* Use memory synchronization variable*/ +}; + +/* Encodings for vectors which can be registered by the OS with SAL */ +enum { + SAL_VECTOR_OS_MCA = 0, + SAL_VECTOR_OS_INIT = 1, + SAL_VECTOR_OS_BOOT_RENDEZ = 2 +}; + +/* Encodings for mca_opt parameter sent to SAL_MC_SET_PARAMS */ +#define SAL_MC_PARAM_RZ_ALWAYS 0x1 +#define SAL_MC_PARAM_BINIT_ESCALATE 0x10 + +/* + * Definition of the SAL Error Log from the SAL spec + */ + +/* SAL Error Record Section GUID Definitions */ +#define SAL_PROC_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf1, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_MEM_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf2, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_SEL_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf3, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_PCI_BUS_ERR_SECT_GUID \ + EFI_GUID(0xe429faf4, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID \ + EFI_GUID(0xe429faf5, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_PCI_COMP_ERR_SECT_GUID \ + EFI_GUID(0xe429faf6, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_SPECIFIC_ERR_SECT_GUID \ + EFI_GUID(0xe429faf7, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_HOST_CTLR_ERR_SECT_GUID \ + EFI_GUID(0xe429faf8, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) +#define SAL_PLAT_BUS_ERR_SECT_GUID \ + EFI_GUID(0xe429faf9, 0x3cb7, 0x11d4, 0xbc, 0xa7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81) + +#define MAX_CACHE_ERRORS 6 +#define MAX_TLB_ERRORS 6 +#define MAX_BUS_ERRORS 1 + +/* Definition of version according to SAL spec for logging purposes */ +typedef struct sal_log_revision { + u8 minor; /* BCD (0..99) */ + u8 major; /* BCD (0..99) */ +} sal_log_revision_t; + +/* Definition of timestamp according to SAL spec for logging purposes */ +typedef struct sal_log_timestamp { + u8 slh_second; /* Second (0..59) */ + u8 slh_minute; /* Minute (0..59) */ + u8 slh_hour; /* Hour (0..23) */ + u8 slh_reserved; + u8 slh_day; /* Day (1..31) */ + u8 slh_month; /* Month (1..12) */ + u8 slh_year; /* Year (00..99) */ + u8 slh_century; /* Century (19, 20, 21, ...) */ +} sal_log_timestamp_t; + +/* Definition of log record header structures */ +typedef struct sal_log_record_header { + u64 id; /* Unique monotonically increasing ID */ + sal_log_revision_t revision; /* Major and Minor revision of header */ + u8 severity; /* Error Severity */ + u8 validation_bits; /* 0: platform_guid, 1: !timestamp */ + u32 len; /* Length of this error log in bytes */ + sal_log_timestamp_t timestamp; /* Timestamp */ + efi_guid_t platform_guid; /* Unique OEM Platform ID */ +} sal_log_record_header_t; + +#define sal_log_severity_recoverable 0 +#define sal_log_severity_fatal 1 +#define sal_log_severity_corrected 2 + +/* Definition of log section header structures */ +typedef struct sal_log_sec_header { + efi_guid_t guid; /* Unique Section ID */ + sal_log_revision_t revision; /* Major and Minor revision of Section */ + u16 reserved; + u32 len; /* Section length */ +} sal_log_section_hdr_t; + +typedef struct sal_log_mod_error_info { + struct { + u64 check_info : 1, + requestor_identifier : 1, + responder_identifier : 1, + target_identifier : 1, + precise_ip : 1, + reserved : 59; + } valid; + u64 check_info; + u64 requestor_identifier; + u64 responder_identifier; + u64 target_identifier; + u64 precise_ip; +} sal_log_mod_error_info_t; + +typedef struct sal_processor_static_info { + struct { + u64 minstate : 1, + br : 1, + cr : 1, + ar : 1, + rr : 1, + fr : 1, + reserved : 58; + } valid; + pal_min_state_area_t min_state_area; + u64 br[8]; + u64 cr[128]; + u64 ar[128]; + u64 rr[8]; + struct ia64_fpreg __attribute__ ((packed)) fr[128]; +} sal_processor_static_info_t; + +struct sal_cpuid_info { + u64 regs[5]; + u64 reserved; +}; + +typedef struct sal_log_processor_info { + sal_log_section_hdr_t header; + struct { + u64 proc_error_map : 1, + proc_state_param : 1, + proc_cr_lid : 1, + psi_static_struct : 1, + num_cache_check : 4, + num_tlb_check : 4, + num_bus_check : 4, + num_reg_file_check : 4, + num_ms_check : 4, + cpuid_info : 1, + reserved1 : 39; + } valid; + u64 proc_error_map; + u64 proc_state_parameter; + u64 proc_cr_lid; + /* + * The rest of this structure consists of variable-length arrays, which can't be + * expressed in C. + */ + sal_log_mod_error_info_t info[0]; + /* + * This is what the rest looked like if C supported variable-length arrays: + * + * sal_log_mod_error_info_t cache_check_info[.valid.num_cache_check]; + * sal_log_mod_error_info_t tlb_check_info[.valid.num_tlb_check]; + * sal_log_mod_error_info_t bus_check_info[.valid.num_bus_check]; + * sal_log_mod_error_info_t reg_file_check_info[.valid.num_reg_file_check]; + * sal_log_mod_error_info_t ms_check_info[.valid.num_ms_check]; + * struct sal_cpuid_info cpuid_info; + * sal_processor_static_info_t processor_static_info; + */ +} sal_log_processor_info_t; + +/* Given a sal_log_processor_info_t pointer, return a pointer to the processor_static_info: */ +#define SAL_LPI_PSI_INFO(l) \ +({ sal_log_processor_info_t *_l = (l); \ + ((sal_processor_static_info_t *) \ + ((char *) _l->info + ((_l->valid.num_cache_check + _l->valid.num_tlb_check \ + + _l->valid.num_bus_check + _l->valid.num_reg_file_check \ + + _l->valid.num_ms_check) * sizeof(sal_log_mod_error_info_t) \ + + sizeof(struct sal_cpuid_info)))); \ +}) + +/* platform error log structures */ + +typedef struct sal_log_mem_dev_err_info { + sal_log_section_hdr_t header; + struct { + u64 error_status : 1, + physical_addr : 1, + addr_mask : 1, + node : 1, + card : 1, + module : 1, + bank : 1, + device : 1, + row : 1, + column : 1, + bit_position : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_id : 1, + oem_data : 1, + reserved : 47; + } valid; + u64 error_status; + u64 physical_addr; + u64 addr_mask; + u16 node; + u16 card; + u16 module; + u16 bank; + u16 device; + u16 row; + u16 column; + u16 bit_position; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_id[16]; + u8 oem_data[1]; /* Variable length data */ +} sal_log_mem_dev_err_info_t; + +typedef struct sal_log_sel_dev_err_info { + sal_log_section_hdr_t header; + struct { + u64 record_id : 1, + record_type : 1, + generator_id : 1, + evm_rev : 1, + sensor_type : 1, + sensor_num : 1, + event_dir : 1, + event_data1 : 1, + event_data2 : 1, + event_data3 : 1, + reserved : 54; + } valid; + u16 record_id; + u8 record_type; + u8 timestamp[4]; + u16 generator_id; + u8 evm_rev; + u8 sensor_type; + u8 sensor_num; + u8 event_dir; + u8 event_data1; + u8 event_data2; + u8 event_data3; +} sal_log_sel_dev_err_info_t; + +typedef struct sal_log_pci_bus_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + err_type : 1, + bus_id : 1, + bus_address : 1, + bus_data : 1, + bus_cmd : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + oem_data : 1, + reserved : 54; + } valid; + u64 err_status; + u16 err_type; + u16 bus_id; + u32 reserved; + u64 bus_address; + u64 bus_data; + u64 bus_cmd; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u8 oem_data[1]; /* Variable length data */ +} sal_log_pci_bus_err_info_t; + +typedef struct sal_log_smbios_dev_err_info { + sal_log_section_hdr_t header; + struct { + u64 event_type : 1, + length : 1, + time_stamp : 1, + data : 1, + reserved1 : 60; + } valid; + u8 event_type; + u8 length; + u8 time_stamp[6]; + u8 data[1]; /* data of variable length, length == slsmb_length */ +} sal_log_smbios_dev_err_info_t; + +typedef struct sal_log_pci_comp_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + comp_info : 1, + num_mem_regs : 1, + num_io_regs : 1, + reg_data_pairs : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + struct { + u16 vendor_id; + u16 device_id; + u8 class_code[3]; + u8 func_num; + u8 dev_num; + u8 bus_num; + u8 seg_num; + u8 reserved[5]; + } comp_info; + u32 num_mem_regs; + u32 num_io_regs; + u64 reg_data_pairs[1]; + /* + * array of address/data register pairs is num_mem_regs + num_io_regs elements + * long. Each array element consists of a u64 address followed by a u64 data + * value. The oem_data array immediately follows the reg_data_pairs array + */ + u8 oem_data[1]; /* Variable length data */ +} sal_log_pci_comp_err_info_t; + +typedef struct sal_log_plat_specific_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + guid : 1, + oem_data : 1, + reserved : 61; + } valid; + u64 err_status; + efi_guid_t guid; + u8 oem_data[1]; /* platform specific variable length data */ +} sal_log_plat_specific_err_info_t; + +typedef struct sal_log_host_ctlr_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_data[1]; /* Variable length OEM data */ +} sal_log_host_ctlr_err_info_t; + +typedef struct sal_log_plat_bus_err_info { + sal_log_section_hdr_t header; + struct { + u64 err_status : 1, + requestor_id : 1, + responder_id : 1, + target_id : 1, + bus_spec_data : 1, + oem_data : 1, + reserved : 58; + } valid; + u64 err_status; + u64 requestor_id; + u64 responder_id; + u64 target_id; + u64 bus_spec_data; + u8 oem_data[1]; /* Variable length OEM data */ +} sal_log_plat_bus_err_info_t; + +/* Overall platform error section structure */ +typedef union sal_log_platform_err_info { + sal_log_mem_dev_err_info_t mem_dev_err; + sal_log_sel_dev_err_info_t sel_dev_err; + sal_log_pci_bus_err_info_t pci_bus_err; + sal_log_smbios_dev_err_info_t smbios_dev_err; + sal_log_pci_comp_err_info_t pci_comp_err; + sal_log_plat_specific_err_info_t plat_specific_err; + sal_log_host_ctlr_err_info_t host_ctlr_err; + sal_log_plat_bus_err_info_t plat_bus_err; +} sal_log_platform_err_info_t; + +/* SAL log over-all, multi-section error record structure (processor+platform) */ +typedef struct err_rec { + sal_log_record_header_t sal_elog_header; + sal_log_processor_info_t proc_err; + sal_log_platform_err_info_t plat_err; + u8 oem_data_pad[1024]; +} ia64_err_rec_t; + +/* + * Now define a couple of inline functions for improved type checking + * and convenience. + */ +static inline long +ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second, + unsigned long *drift_info) +{ + struct ia64_sal_retval isrv; + + SAL_CALL(isrv, SAL_FREQ_BASE, which, 0, 0, 0, 0, 0, 0); + *ticks_per_second = isrv.v0; + *drift_info = isrv.v1; + return isrv.status; +} + +extern s64 ia64_sal_cache_flush (u64 cache_type); + +/* Initialize all the processor and platform level instruction and data caches */ +static inline s64 +ia64_sal_cache_init (void) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_CACHE_INIT, 0, 0, 0, 0, 0, 0, 0); + return isrv.status; +} + +/* + * Clear the processor and platform information logged by SAL with respect to the machine + * state at the time of MCA's, INITs, CMCs, or CPEs. + */ +static inline s64 +ia64_sal_clear_state_info (u64 sal_info_type) +{ + struct ia64_sal_retval isrv; + SAL_CALL_REENTRANT(isrv, SAL_CLEAR_STATE_INFO, sal_info_type, 0, + 0, 0, 0, 0, 0); + return isrv.status; +} + + +/* Get the processor and platform information logged by SAL with respect to the machine + * state at the time of the MCAs, INITs, CMCs, or CPEs. + */ +static inline u64 +ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) +{ + struct ia64_sal_retval isrv; + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, + sal_info, 0, 0, 0, 0); + if (isrv.status) + return 0; + + return isrv.v0; +} + +/* + * Get the maximum size of the information logged by SAL with respect to the machine state + * at the time of MCAs, INITs, CMCs, or CPEs. + */ +static inline u64 +ia64_sal_get_state_info_size (u64 sal_info_type) +{ + struct ia64_sal_retval isrv; + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO_SIZE, sal_info_type, 0, + 0, 0, 0, 0, 0); + if (isrv.status) + return 0; + return isrv.v0; +} + +/* + * Causes the processor to go into a spin loop within SAL where SAL awaits a wakeup from + * the monarch processor. Must not lock, because it will not return on any cpu until the + * monarch processor sends a wake up. + */ +static inline s64 +ia64_sal_mc_rendez (void) +{ + struct ia64_sal_retval isrv; + SAL_CALL_NOLOCK(isrv, SAL_MC_RENDEZ, 0, 0, 0, 0, 0, 0, 0); + return isrv.status; +} + +/* + * Allow the OS to specify the interrupt number to be used by SAL to interrupt OS during + * the machine check rendezvous sequence as well as the mechanism to wake up the + * non-monarch processor at the end of machine check processing. + * Returns the complete ia64_sal_retval because some calls return more than just a status + * value. + */ +static inline struct ia64_sal_retval +ia64_sal_mc_set_params (u64 param_type, u64 i_or_m, u64 i_or_m_val, u64 timeout, u64 rz_always) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_MC_SET_PARAMS, param_type, i_or_m, i_or_m_val, + timeout, rz_always, 0, 0); + return isrv; +} + +/* Read from PCI configuration space */ +static inline s64 +ia64_sal_pci_config_read (u64 pci_config_addr, int type, u64 size, u64 *value) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PCI_CONFIG_READ, pci_config_addr, size, type, 0, 0, 0, 0); + if (value) + *value = isrv.v0; + return isrv.status; +} + +/* Write to PCI configuration space */ +static inline s64 +ia64_sal_pci_config_write (u64 pci_config_addr, int type, u64 size, u64 value) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PCI_CONFIG_WRITE, pci_config_addr, size, value, + type, 0, 0, 0); + return isrv.status; +} + +/* + * Register physical addresses of locations needed by SAL when SAL procedures are invoked + * in virtual mode. + */ +static inline s64 +ia64_sal_register_physical_addr (u64 phys_entry, u64 phys_addr) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_REGISTER_PHYSICAL_ADDR, phys_entry, phys_addr, + 0, 0, 0, 0, 0); + return isrv.status; +} + +/* + * Register software dependent code locations within SAL. These locations are handlers or + * entry points where SAL will pass control for the specified event. These event handlers + * are for the bott rendezvous, MCAs and INIT scenarios. + */ +static inline s64 +ia64_sal_set_vectors (u64 vector_type, + u64 handler_addr1, u64 gp1, u64 handler_len1, + u64 handler_addr2, u64 gp2, u64 handler_len2) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_SET_VECTORS, vector_type, + handler_addr1, gp1, handler_len1, + handler_addr2, gp2, handler_len2); + + return isrv.status; +} + +/* Update the contents of PAL block in the non-volatile storage device */ +static inline s64 +ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size, + u64 *error_code, u64 *scratch_buf_size_needed) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_UPDATE_PAL, param_buf, scratch_buf, scratch_buf_size, + 0, 0, 0, 0); + if (error_code) + *error_code = isrv.v0; + if (scratch_buf_size_needed) + *scratch_buf_size_needed = isrv.v1; + return isrv.status; +} + +/* Get physical processor die mapping in the platform. */ +static inline s64 +ia64_sal_physical_id_info(u16 *splid) +{ + struct ia64_sal_retval isrv; + SAL_CALL(isrv, SAL_PHYSICAL_ID_INFO, 0, 0, 0, 0, 0, 0, 0); + if (splid) + *splid = isrv.v0; + return isrv.status; +} + +extern unsigned long sal_platform_features; + +extern int (*salinfo_platform_oemdata)(const u8 *, u8 **, u64 *); + +struct sal_ret_values { + long r8; long r9; long r10; long r11; +}; + +#define IA64_SAL_OEMFUNC_MIN 0x02000000 +#define IA64_SAL_OEMFUNC_MAX 0x03ffffff + +extern int ia64_sal_oemcall(struct ia64_sal_retval *, u64, u64, u64, u64, u64, + u64, u64, u64); +extern int ia64_sal_oemcall_nolock(struct ia64_sal_retval *, u64, u64, u64, + u64, u64, u64, u64, u64); +extern int ia64_sal_oemcall_reentrant(struct ia64_sal_retval *, u64, u64, u64, + u64, u64, u64, u64, u64); +#ifdef CONFIG_HOTPLUG_CPU +/* + * System Abstraction Layer Specification + * Section 3.2.5.1: OS_BOOT_RENDEZ to SAL return State. + * Note: region regs are stored first in head.S _start. Hence they must + * stay up front. + */ +struct sal_to_os_boot { + u64 rr[8]; /* Region Registers */ + u64 br[6]; /* br0: return addr into SAL boot rendez routine */ + u64 gr1; /* SAL:GP */ + u64 gr12; /* SAL:SP */ + u64 gr13; /* SAL: Task Pointer */ + u64 fpsr; + u64 pfs; + u64 rnat; + u64 unat; + u64 bspstore; + u64 dcr; /* Default Control Register */ + u64 iva; + u64 pta; + u64 itv; + u64 pmv; + u64 cmcv; + u64 lrr[2]; + u64 gr[4]; + u64 pr; /* Predicate registers */ + u64 lc; /* Loop Count */ + struct ia64_fpreg fp[20]; +}; + +/* + * Global array allocated for NR_CPUS at boot time + */ +extern struct sal_to_os_boot sal_boot_rendez_state[NR_CPUS]; + +extern void ia64_jump_to_sal(struct sal_to_os_boot *); +#endif + +extern void ia64_sal_handler_init(void *entry_point, void *gpval); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_IA64_SAL_H */ From 2993e9e5bb591c39e0bbbad16aff23fe286b5338 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:18 -0700 Subject: [PATCH 009/282] [IA64] MCA support - use xencomm to copy SAL error log Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- linux-2.6-xen-sparse/include/asm-ia64/sal.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/linux-2.6-xen-sparse/include/asm-ia64/sal.h b/linux-2.6-xen-sparse/include/asm-ia64/sal.h index 0b210abbe0..0cda1c410b 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/sal.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/sal.h @@ -42,6 +42,9 @@ #include #include #include +#ifdef CONFIG_XEN +#include +#endif extern spinlock_t sal_lock; @@ -686,10 +689,28 @@ ia64_sal_clear_state_info (u64 sal_info_type) /* Get the processor and platform information logged by SAL with respect to the machine * state at the time of the MCAs, INITs, CMCs, or CPEs. */ +#ifdef CONFIG_XEN +static inline u64 ia64_sal_get_state_info_size (u64 sal_info_type); +#endif + static inline u64 ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) { struct ia64_sal_retval isrv; +#ifdef CONFIG_XEN + if (is_running_on_xen()) { + struct xencomm_mini xc_area[2]; + int nbr_area = 2; + struct xencomm_handle *desc; + + if (xencomm_create_mini(xc_area, &nbr_area, sal_info, + ia64_sal_get_state_info_size(sal_info_type), &desc)) + return 0; + + SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, + desc, 0, 0, 0, 0); + } else +#endif SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, sal_info, 0, 0, 0, 0); if (isrv.status) From 324df3e3dfb80bba59ea143cbb8a0ee18cc2162d Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:19 -0700 Subject: [PATCH 010/282] [IA64] MCA support - Add lid and percpu paddr table Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/xen/mm_init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/xen/mm_init.c b/xen/arch/ia64/xen/mm_init.c index f9a44a43de..cecb879551 100644 --- a/xen/arch/ia64/xen/mm_init.c +++ b/xen/arch/ia64/xen/mm_init.c @@ -10,6 +10,11 @@ #include #include +#include +#include +#include + +struct ia64_mca_tlb_info ia64_mca_tlb_list[NR_CPUS]; extern void ia64_tlb_init (void); @@ -93,11 +98,13 @@ ia64_mmu_init (void *my_cpu_data) cpu = smp_processor_id(); -#ifndef XEN /* mca handler uses cr.lid as key to pick the right entry */ ia64_mca_tlb_list[cpu].cr_lid = ia64_getreg(_IA64_REG_CR_LID); /* insert this percpu data information into our list for MCA recovery purposes */ +#ifdef XEN + ia64_mca_tlb_list[cpu].percpu_paddr = __pa(my_cpu_data); +#else ia64_mca_tlb_list[cpu].percpu_paddr = pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)); /* Also save per-cpu tlb flush recipe for use in physical mode mca handler */ ia64_mca_tlb_list[cpu].ptce_base = local_cpu_data->ptce_base; From 252d2db3d74227880a6bf5ed696f116270a1ad55 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:20 -0700 Subject: [PATCH 011/282] [IA64] MCA support - smpboot support for MCA Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/linux-xen/smpboot.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/xen/arch/ia64/linux-xen/smpboot.c b/xen/arch/ia64/linux-xen/smpboot.c index 4450ce9260..6a48aaf1de 100644 --- a/xen/arch/ia64/linux-xen/smpboot.c +++ b/xen/arch/ia64/linux-xen/smpboot.c @@ -365,9 +365,7 @@ smp_callin (void) smp_setup_percpu_timer(); -#ifndef XEN ia64_mca_cmc_vector_setup(); /* Setup vector on AP */ -#endif #ifdef CONFIG_PERFMON pfm_init_percpu(); From d8145049eba3485b94c51ef6d396430db0e735e3 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:21 -0700 Subject: [PATCH 012/282] [IA64] MCA support - Add MCA offset entry Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/asm-offsets.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 32a7d076aa..715baa6e30 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -12,6 +12,7 @@ #include #include #include +#include #define task_struct vcpu @@ -220,4 +221,37 @@ void foo(void) DEFINE(FAST_HYPERPRIVOP_PERFC_OFS, offsetof (struct perfcounter, fast_hyperprivop)); DEFINE(FAST_REFLECT_PERFC_OFS, offsetof (struct perfcounter, fast_reflect)); #endif + + BLANK(); + DEFINE(IA64_CPUINFO_PTCE_BASE_OFFSET, + offsetof(struct cpuinfo_ia64, ptce_base)); + DEFINE(IA64_CPUINFO_PTCE_COUNT_OFFSET, + offsetof(struct cpuinfo_ia64, ptce_count)); + DEFINE(IA64_CPUINFO_PTCE_STRIDE_OFFSET, + offsetof(struct cpuinfo_ia64, ptce_stride)); + + BLANK(); + DEFINE(IA64_MCA_CPU_PROC_STATE_DUMP_OFFSET, + offsetof(struct ia64_mca_cpu, proc_state_dump)); + DEFINE(IA64_MCA_CPU_STACK_OFFSET, + offsetof(struct ia64_mca_cpu, stack)); + DEFINE(IA64_MCA_CPU_STACKFRAME_OFFSET, + offsetof(struct ia64_mca_cpu, stackframe)); + DEFINE(IA64_MCA_CPU_RBSTORE_OFFSET, + offsetof(struct ia64_mca_cpu, rbstore)); + + DEFINE(IA64_DOMAIN_SHARED_INFO_OFFSET, + offsetof(struct domain, shared_info)); + DEFINE(IA64_DOMAIN_SHARED_INFO_VA_OFFSET, + offsetof(struct domain, arch.shared_info_va)); + DEFINE(IA64_DOMAIN_FLAGS_OFFSET, + offsetof(struct domain, arch.flags)); + + DEFINE(IA64_VCPU_VHPT_MADDR_OFFSET, + offsetof(struct vcpu, arch.vhpt_maddr)); + + BLANK(); + DEFINE(IA64_MCA_TLB_INFO_SIZE, sizeof(struct ia64_mca_tlb_info)); + DEFINE(IA64_MCA_PERCPU_OFFSET, + offsetof(struct ia64_mca_tlb_info, percpu_paddr)); } From 205c39876d9c829bfa97c3ae12a964c184f2ea6c Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:23 -0700 Subject: [PATCH 013/282] [IA64] MCA support - Define VIRQs for MCA Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/include/public/arch-ia64.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index 78f0d57dbf..b8d325c7a6 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -40,6 +40,8 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); /* Arch specific VIRQs definition */ #define VIRQ_ITC VIRQ_ARCH_0 /* V. Virtual itc timer */ +#define VIRQ_MCA_CMC VIRQ_ARCH_1 /* MCA cmc interrupt */ +#define VIRQ_MCA_CPE VIRQ_ARCH_2 /* MCA cpe interrupt */ /* Maximum number of virtual CPUs in multi-processor guests. */ /* WARNING: before changing this, check that shared_info fits on a page */ From c17389c371e694fbc8a9a11ce5b234a19c195c37 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:24 -0700 Subject: [PATCH 014/282] [IA64] MCA support - Add softirq handle for MCA Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/include/xen/softirq.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h index 00e561dc86..977a1ad5dc 100644 --- a/xen/include/xen/softirq.h +++ b/xen/include/xen/softirq.h @@ -10,7 +10,13 @@ #define PAGE_SCRUB_SOFTIRQ 5 #define DOMAIN_SHUTDOWN_FINALISE_SOFTIRQ 6 #define TRACE_SOFTIRQ 7 +#ifdef __ia64__ +#define CMC_DISABLE_SOFTIRQ 8 +#define CMC_ENABLE_SOFTIRQ 9 +#define NR_SOFTIRQS 10 +#else /* __ia64__ */ #define NR_SOFTIRQS 8 +#endif /* __ia64__ */ #ifndef __ASSEMBLY__ From 068186597a403c08f53f0ae03444ed38d49abedb Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:25 -0700 Subject: [PATCH 015/282] [IA64] MCA support - Fix UINT64 & BOOLEAN typedefs Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/include/asm-ia64/vcpu.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h index a95d3f1c29..b61915e3b2 100644 --- a/xen/include/asm-ia64/vcpu.h +++ b/xen/include/asm-ia64/vcpu.h @@ -10,7 +10,7 @@ #include #include #include -typedef int BOOLEAN; +#include struct vcpu; typedef struct vcpu VCPU; typedef cpu_user_regs_t REGS; From 581b1647c53e1824cacdda3b767122f4891cfb65 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sun, 29 Oct 2006 09:27:26 -0700 Subject: [PATCH 016/282] [IA64] warning fix These are pulled in through the ACPI header now Signed-off-by: Alex Williamson --- xen/arch/ia64/xen/vcpu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/xen/arch/ia64/xen/vcpu.c b/xen/arch/ia64/xen/vcpu.c index 63d91576b7..6748fbe539 100644 --- a/xen/arch/ia64/xen/vcpu.c +++ b/xen/arch/ia64/xen/vcpu.c @@ -46,8 +46,6 @@ typedef union { // this def for vcpu_regs won't work if kernel stack is present //#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs -#define TRUE 1 -#define FALSE 0 #define IA64_PTA_SZ_BIT 2 #define IA64_PTA_VF_BIT 8 #define IA64_PTA_BASE_BIT 15 From 3bd852f20785c5c1656751fbdc3aa8de4701672b Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 28 Nov 2006 15:25:26 +0000 Subject: [PATCH 017/282] [LINUX] Update to 2.6.16.33. No changes required to sparse tree or patches directory. Signed-off-by: Ian Campbell --- buildconfigs/mk.linux-2.6-xen | 2 +- .../blktap-aio-16_03_06.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/device_bind.patch | 0 .../{linux-2.6.16.32 => linux-2.6.16.33}/fix-hz-suspend.patch | 0 .../fix-ide-cd-pio-mode.patch | 0 .../i386-mach-io-check-nmi.patch | 0 .../{linux-2.6.16.32 => linux-2.6.16.33}/ipv6-no-autoconf.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/kasprintf.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-csum.patch | 0 .../{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-0-base.patch | 0 .../net-gso-1-check-dodgy.patch | 0 .../net-gso-2-checksum-fix.patch | 0 .../net-gso-3-fix-errorcheck.patch | 0 .../net-gso-4-kill-warnon.patch | 0 .../net-gso-5-rcv-mss.patch | 0 .../pci-mmconfig-fix-from-2.6.17.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/pmd-shared.patch | 0 .../{linux-2.6.16.32 => linux-2.6.16.33}/rcu_needs_cpu.patch | 0 .../rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/series | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/smp-alts.patch | 0 .../tpm_plugin_2.6.17.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/vsnprintf.patch | 0 .../x86-elfnote-as-preprocessor-macro.patch | 0 .../x86-increase-interrupt-vector-range.patch | 0 ...86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch | 0 ...64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch | 0 patches/{linux-2.6.16.32 => linux-2.6.16.33}/xen-hotplug.patch | 0 .../{linux-2.6.16.32 => linux-2.6.16.33}/xenoprof-generic.patch | 0 29 files changed, 1 insertion(+), 1 deletion(-) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/blktap-aio-16_03_06.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/device_bind.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/fix-hz-suspend.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/fix-ide-cd-pio-mode.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/i386-mach-io-check-nmi.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/ipv6-no-autoconf.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/kasprintf.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-csum.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-0-base.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-1-check-dodgy.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-2-checksum-fix.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-3-fix-errorcheck.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-4-kill-warnon.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/net-gso-5-rcv-mss.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/pci-mmconfig-fix-from-2.6.17.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/pmd-shared.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/rcu_needs_cpu.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/series (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/smp-alts.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/tpm_plugin_2.6.17.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/vsnprintf.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/x86-elfnote-as-preprocessor-macro.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/x86-increase-interrupt-vector-range.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/xen-hotplug.patch (100%) rename patches/{linux-2.6.16.32 => linux-2.6.16.33}/xenoprof-generic.patch (100%) diff --git a/buildconfigs/mk.linux-2.6-xen b/buildconfigs/mk.linux-2.6-xen index 72bd77ed89..9a1e47a332 100644 --- a/buildconfigs/mk.linux-2.6-xen +++ b/buildconfigs/mk.linux-2.6-xen @@ -1,5 +1,5 @@ LINUX_SERIES = 2.6 -LINUX_VER = 2.6.16.32 +LINUX_VER = 2.6.16.33 EXTRAVERSION ?= xen diff --git a/patches/linux-2.6.16.32/blktap-aio-16_03_06.patch b/patches/linux-2.6.16.33/blktap-aio-16_03_06.patch similarity index 100% rename from patches/linux-2.6.16.32/blktap-aio-16_03_06.patch rename to patches/linux-2.6.16.33/blktap-aio-16_03_06.patch diff --git a/patches/linux-2.6.16.32/device_bind.patch b/patches/linux-2.6.16.33/device_bind.patch similarity index 100% rename from patches/linux-2.6.16.32/device_bind.patch rename to patches/linux-2.6.16.33/device_bind.patch diff --git a/patches/linux-2.6.16.32/fix-hz-suspend.patch b/patches/linux-2.6.16.33/fix-hz-suspend.patch similarity index 100% rename from patches/linux-2.6.16.32/fix-hz-suspend.patch rename to patches/linux-2.6.16.33/fix-hz-suspend.patch diff --git a/patches/linux-2.6.16.32/fix-ide-cd-pio-mode.patch b/patches/linux-2.6.16.33/fix-ide-cd-pio-mode.patch similarity index 100% rename from patches/linux-2.6.16.32/fix-ide-cd-pio-mode.patch rename to patches/linux-2.6.16.33/fix-ide-cd-pio-mode.patch diff --git a/patches/linux-2.6.16.32/i386-mach-io-check-nmi.patch b/patches/linux-2.6.16.33/i386-mach-io-check-nmi.patch similarity index 100% rename from patches/linux-2.6.16.32/i386-mach-io-check-nmi.patch rename to patches/linux-2.6.16.33/i386-mach-io-check-nmi.patch diff --git a/patches/linux-2.6.16.32/ipv6-no-autoconf.patch b/patches/linux-2.6.16.33/ipv6-no-autoconf.patch similarity index 100% rename from patches/linux-2.6.16.32/ipv6-no-autoconf.patch rename to patches/linux-2.6.16.33/ipv6-no-autoconf.patch diff --git a/patches/linux-2.6.16.32/kasprintf.patch b/patches/linux-2.6.16.33/kasprintf.patch similarity index 100% rename from patches/linux-2.6.16.32/kasprintf.patch rename to patches/linux-2.6.16.33/kasprintf.patch diff --git a/patches/linux-2.6.16.32/net-csum.patch b/patches/linux-2.6.16.33/net-csum.patch similarity index 100% rename from patches/linux-2.6.16.32/net-csum.patch rename to patches/linux-2.6.16.33/net-csum.patch diff --git a/patches/linux-2.6.16.32/net-gso-0-base.patch b/patches/linux-2.6.16.33/net-gso-0-base.patch similarity index 100% rename from patches/linux-2.6.16.32/net-gso-0-base.patch rename to patches/linux-2.6.16.33/net-gso-0-base.patch diff --git a/patches/linux-2.6.16.32/net-gso-1-check-dodgy.patch b/patches/linux-2.6.16.33/net-gso-1-check-dodgy.patch similarity index 100% rename from patches/linux-2.6.16.32/net-gso-1-check-dodgy.patch rename to patches/linux-2.6.16.33/net-gso-1-check-dodgy.patch diff --git a/patches/linux-2.6.16.32/net-gso-2-checksum-fix.patch b/patches/linux-2.6.16.33/net-gso-2-checksum-fix.patch similarity index 100% rename from patches/linux-2.6.16.32/net-gso-2-checksum-fix.patch rename to patches/linux-2.6.16.33/net-gso-2-checksum-fix.patch diff --git a/patches/linux-2.6.16.32/net-gso-3-fix-errorcheck.patch b/patches/linux-2.6.16.33/net-gso-3-fix-errorcheck.patch similarity index 100% rename from patches/linux-2.6.16.32/net-gso-3-fix-errorcheck.patch rename to patches/linux-2.6.16.33/net-gso-3-fix-errorcheck.patch diff --git a/patches/linux-2.6.16.32/net-gso-4-kill-warnon.patch b/patches/linux-2.6.16.33/net-gso-4-kill-warnon.patch similarity index 100% rename from patches/linux-2.6.16.32/net-gso-4-kill-warnon.patch rename to patches/linux-2.6.16.33/net-gso-4-kill-warnon.patch diff --git a/patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch b/patches/linux-2.6.16.33/net-gso-5-rcv-mss.patch similarity index 100% rename from patches/linux-2.6.16.32/net-gso-5-rcv-mss.patch rename to patches/linux-2.6.16.33/net-gso-5-rcv-mss.patch diff --git a/patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch b/patches/linux-2.6.16.33/pci-mmconfig-fix-from-2.6.17.patch similarity index 100% rename from patches/linux-2.6.16.32/pci-mmconfig-fix-from-2.6.17.patch rename to patches/linux-2.6.16.33/pci-mmconfig-fix-from-2.6.17.patch diff --git a/patches/linux-2.6.16.32/pmd-shared.patch b/patches/linux-2.6.16.33/pmd-shared.patch similarity index 100% rename from patches/linux-2.6.16.32/pmd-shared.patch rename to patches/linux-2.6.16.33/pmd-shared.patch diff --git a/patches/linux-2.6.16.32/rcu_needs_cpu.patch b/patches/linux-2.6.16.33/rcu_needs_cpu.patch similarity index 100% rename from patches/linux-2.6.16.32/rcu_needs_cpu.patch rename to patches/linux-2.6.16.33/rcu_needs_cpu.patch diff --git a/patches/linux-2.6.16.32/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch b/patches/linux-2.6.16.33/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch similarity index 100% rename from patches/linux-2.6.16.32/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch rename to patches/linux-2.6.16.33/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch diff --git a/patches/linux-2.6.16.32/series b/patches/linux-2.6.16.33/series similarity index 100% rename from patches/linux-2.6.16.32/series rename to patches/linux-2.6.16.33/series diff --git a/patches/linux-2.6.16.32/smp-alts.patch b/patches/linux-2.6.16.33/smp-alts.patch similarity index 100% rename from patches/linux-2.6.16.32/smp-alts.patch rename to patches/linux-2.6.16.33/smp-alts.patch diff --git a/patches/linux-2.6.16.32/tpm_plugin_2.6.17.patch b/patches/linux-2.6.16.33/tpm_plugin_2.6.17.patch similarity index 100% rename from patches/linux-2.6.16.32/tpm_plugin_2.6.17.patch rename to patches/linux-2.6.16.33/tpm_plugin_2.6.17.patch diff --git a/patches/linux-2.6.16.32/vsnprintf.patch b/patches/linux-2.6.16.33/vsnprintf.patch similarity index 100% rename from patches/linux-2.6.16.32/vsnprintf.patch rename to patches/linux-2.6.16.33/vsnprintf.patch diff --git a/patches/linux-2.6.16.32/x86-elfnote-as-preprocessor-macro.patch b/patches/linux-2.6.16.33/x86-elfnote-as-preprocessor-macro.patch similarity index 100% rename from patches/linux-2.6.16.32/x86-elfnote-as-preprocessor-macro.patch rename to patches/linux-2.6.16.33/x86-elfnote-as-preprocessor-macro.patch diff --git a/patches/linux-2.6.16.32/x86-increase-interrupt-vector-range.patch b/patches/linux-2.6.16.33/x86-increase-interrupt-vector-range.patch similarity index 100% rename from patches/linux-2.6.16.32/x86-increase-interrupt-vector-range.patch rename to patches/linux-2.6.16.33/x86-increase-interrupt-vector-range.patch diff --git a/patches/linux-2.6.16.32/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch b/patches/linux-2.6.16.33/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch similarity index 100% rename from patches/linux-2.6.16.32/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch rename to patches/linux-2.6.16.33/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch diff --git a/patches/linux-2.6.16.32/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch b/patches/linux-2.6.16.33/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch similarity index 100% rename from patches/linux-2.6.16.32/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch rename to patches/linux-2.6.16.33/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch diff --git a/patches/linux-2.6.16.32/xen-hotplug.patch b/patches/linux-2.6.16.33/xen-hotplug.patch similarity index 100% rename from patches/linux-2.6.16.32/xen-hotplug.patch rename to patches/linux-2.6.16.33/xen-hotplug.patch diff --git a/patches/linux-2.6.16.32/xenoprof-generic.patch b/patches/linux-2.6.16.33/xenoprof-generic.patch similarity index 100% rename from patches/linux-2.6.16.32/xenoprof-generic.patch rename to patches/linux-2.6.16.33/xenoprof-generic.patch From db08b83ada0a53536ea4bc98834526b4a08777fb Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 28 Nov 2006 15:47:52 +0000 Subject: [PATCH 018/282] [HVMLOADER][ACPI] Move SSDT initialisation to acpi/ dir. This kills off a few hundred lines of unnecessary code. Signed-off-by: Keir Fraser --- tools/firmware/hvmloader/Makefile | 4 +- tools/firmware/hvmloader/acpi/Makefile | 8 +- tools/firmware/hvmloader/acpi/acpi2_0.h | 15 +- tools/firmware/hvmloader/acpi/build.c | 114 ++++--- .../{acpi_ssdt_tpm.asl => acpi/ssdt_tpm.asl} | 0 .../{acpi_ssdt_tpm.h => acpi/ssdt_tpm.h} | 0 tools/firmware/hvmloader/acpi_utils.c | 318 ------------------ tools/firmware/hvmloader/acpi_utils.h | 36 -- tools/firmware/hvmloader/hvmloader.c | 9 +- tools/firmware/hvmloader/mp_tables.c | 1 - tools/firmware/hvmloader/util.h | 3 + 11 files changed, 96 insertions(+), 412 deletions(-) rename tools/firmware/hvmloader/{acpi_ssdt_tpm.asl => acpi/ssdt_tpm.asl} (100%) rename tools/firmware/hvmloader/{acpi_ssdt_tpm.h => acpi/ssdt_tpm.h} (100%) delete mode 100644 tools/firmware/hvmloader/acpi_utils.c delete mode 100644 tools/firmware/hvmloader/acpi_utils.h diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index 4e4502d673..39d8a20fae 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -40,7 +40,7 @@ OBJCOPY = objcopy CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float LDFLAGS = -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR) -SRCS = hvmloader.c mp_tables.c util.c smbios.c acpi_utils.c +SRCS = hvmloader.c mp_tables.c util.c smbios.c OBJS = $(patsubst %.c,%.o,$(SRCS)) .PHONY: all @@ -65,5 +65,5 @@ roms.h: ../rombios/BIOS-bochs-latest ../vgabios/VGABIOS-lgpl-latest.bin ../vgabi .PHONY: clean clean: rm -f roms.h acpi.h - rm -f hvmloader hvmloader.tmp hvmloader.o $(OBJS) + rm -f hvmloader hvmloader.tmp *.o $(MAKE) -C acpi clean diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile index 9aec04735a..cd05e21a5e 100644 --- a/tools/firmware/hvmloader/acpi/Makefile +++ b/tools/firmware/hvmloader/acpi/Makefile @@ -30,12 +30,18 @@ IASL_URL = http://developer.intel.com/technology/iapc/acpi/downloads/$(IASL_VER) vpath iasl $(PATH) all: acpi.a +ssdt_tpm.h: ssdt_tpm.asl + $(MAKE) iasl + iasl -tc ssdt_tpm.asl + mv ssdt_tpm.hex ssdt_tpm.h + rm -f *.aml + dsdt.c: dsdt.asl $(MAKE) iasl iasl -tc dsdt.asl mv dsdt.hex dsdt.c echo "int DsdtLen=sizeof(AmlCode);" >> dsdt.c - rm *.aml + rm -f *.aml iasl: @echo diff --git a/tools/firmware/hvmloader/acpi/acpi2_0.h b/tools/firmware/hvmloader/acpi/acpi2_0.h index 62cb16eeb8..5b9b9f0495 100644 --- a/tools/firmware/hvmloader/acpi/acpi2_0.h +++ b/tools/firmware/hvmloader/acpi/acpi2_0.h @@ -119,7 +119,7 @@ struct acpi_20_rsdp { */ struct acpi_20_rsdt { struct acpi_header header; - uint32_t entry[ACPI_MAX_NUM_TABLES]; + uint32_t entry[1]; }; #define ACPI_2_0_RSDT_REVISION 0x01 @@ -128,20 +128,19 @@ struct acpi_20_rsdt { */ struct acpi_20_xsdt { struct acpi_header header; - uint64_t entry[ACPI_MAX_NUM_TABLES]; + uint64_t entry[1]; }; #define ACPI_2_0_XSDT_REVISION 0x01 /* * TCG Hardware Interface Table (TCPA) */ - -typedef struct _ACPI_2_0_TCPA_CLIENT { +struct acpi_20_tcpa { struct acpi_header header; - uint16_t PlatformClass; - uint32_t LAML; - uint64_t LASA; -} ACPI_2_0_TCPA_CLIENT; + uint16_t platform_class; + uint32_t laml; + uint64_t lasa; +}; #define ACPI_2_0_TCPA_REVISION 0x02 #define ACPI_2_0_TCPA_LAML_SIZE (64*1024) diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c index 68b1e18bb0..241c11332d 100644 --- a/tools/firmware/hvmloader/acpi/build.c +++ b/tools/firmware/hvmloader/acpi/build.c @@ -17,8 +17,12 @@ */ #include "acpi2_0.h" +#include "ssdt_tpm.h" #include "../config.h" #include "../util.h" +#include + +#define align16(sz) (((sz) + 15) & ~15) extern struct acpi_20_rsdp Rsdp; extern struct acpi_20_rsdt Rsdt; @@ -103,39 +107,85 @@ int construct_madt(struct acpi_20_madt *madt) madt->header.length = offset; set_checksum(madt, offsetof(struct acpi_header, checksum), offset); - return offset; + return align16(offset); } -/* - * Copy all the ACPI table to buffer. - * Buffer layout: FACS, DSDT, FADT, MADT, XSDT, RSDT, RSDP. - */ +int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs) +{ + int offset = 0, nr_tables = 0; + struct acpi_20_madt *madt; + struct acpi_20_tcpa *tcpa; + static const uint16_t tis_did_vid_rid[] = {0x0001, 0x0001, 0x0001}; + + /* MADT. */ + if ( (get_vcpu_nr() > 1) || get_apic_mode() ) + { + madt = (struct acpi_20_madt *)&buf[offset]; + offset += construct_madt(madt); + table_ptrs[nr_tables++] = (unsigned long)madt; + } + + /* TPM TCPA and SSDT. */ + if ( memcmp((char *)0xFED40F00, tis_did_vid_rid, + sizeof(tis_did_vid_rid)) == 0 ) /* Probe for TIS interface. */ + { + memcpy(&buf[offset], AmlCode_TPM, sizeof(AmlCode_TPM)); + table_ptrs[nr_tables++] = (unsigned long)&buf[offset]; + offset += align16(sizeof(AmlCode_TPM)); + + tcpa = (struct acpi_20_tcpa *)&buf[offset]; + memset(tcpa, 0, sizeof(*tcpa)); + offset += align16(sizeof(*tcpa)); + table_ptrs[nr_tables++] = (unsigned long)tcpa; + + tcpa->header.signature = ACPI_2_0_TCPA_SIGNATURE; + tcpa->header.length = sizeof(*tcpa); + tcpa->header.revision = ACPI_2_0_TCPA_REVISION; + strncpy(tcpa->header.oem_id, "IBM ", 6); + tcpa->header.oem_table_id = ASCII64(' ', ' ', ' ', ' ', + ' ', 'x', 'e', 'n'); + tcpa->header.oem_revision = 1; + tcpa->header.creator_id = ASCII32('I', 'B', 'M', ' '); + tcpa->header.creator_revision = 1; + tcpa->lasa = e820_malloc( + ACPI_2_0_TCPA_LAML_SIZE, E820_RESERVED, (uint32_t)~0); + if ( tcpa->lasa ) + { + tcpa->laml = ACPI_2_0_TCPA_LAML_SIZE; + memset((char *)(unsigned long)tcpa->lasa, 0, tcpa->laml); + set_checksum(tcpa, + offsetof(struct acpi_header, checksum), + tcpa->header.length); + } + } + + table_ptrs[nr_tables] = 0; + return align16(offset); +} + +/* Copy all the ACPI table to buffer. */ int acpi_build_tables(uint8_t *buf) { struct acpi_20_rsdp *rsdp; struct acpi_20_rsdt *rsdt; struct acpi_20_xsdt *xsdt; struct acpi_20_fadt *fadt; - struct acpi_20_madt *madt = 0; struct acpi_20_facs *facs; unsigned char *dsdt; - int offset = 0, requires_madt; - - requires_madt = ((get_vcpu_nr() > 1) || get_apic_mode()); - -#define inc_offset(sz) (offset = (offset + (sz) + 15) & ~15) + unsigned long secondary_tables[16]; + int offset = 0, i; facs = (struct acpi_20_facs *)&buf[offset]; memcpy(facs, &Facs, sizeof(struct acpi_20_facs)); - inc_offset(sizeof(struct acpi_20_facs)); + offset += align16(sizeof(struct acpi_20_facs)); dsdt = (unsigned char *)&buf[offset]; memcpy(dsdt, &AmlCode, DsdtLen); - inc_offset(DsdtLen); + offset += align16(DsdtLen); fadt = (struct acpi_20_fadt *)&buf[offset]; memcpy(fadt, &Fadt, sizeof(struct acpi_20_fadt)); - inc_offset(sizeof(struct acpi_20_fadt)); + offset += align16(sizeof(struct acpi_20_fadt)); fadt->dsdt = (unsigned long)dsdt; fadt->x_dsdt = (unsigned long)dsdt; fadt->firmware_ctrl = (unsigned long)facs; @@ -144,43 +194,33 @@ int acpi_build_tables(uint8_t *buf) offsetof(struct acpi_header, checksum), sizeof(struct acpi_20_fadt)); - if ( requires_madt ) - { - madt = (struct acpi_20_madt *)&buf[offset]; - inc_offset(construct_madt(madt)); - } + offset += construct_secondary_tables(&buf[offset], secondary_tables); xsdt = (struct acpi_20_xsdt *)&buf[offset]; - memcpy(xsdt, &Xsdt, sizeof(struct acpi_20_xsdt)); - inc_offset(sizeof(struct acpi_20_xsdt)); + memcpy(xsdt, &Xsdt, sizeof(struct acpi_header)); xsdt->entry[0] = (unsigned long)fadt; - xsdt->header.length = sizeof(struct acpi_header) + sizeof(uint64_t); - if ( requires_madt ) - { - xsdt->entry[1] = (unsigned long)madt; - xsdt->header.length += sizeof(uint64_t); - } + for ( i = 0; secondary_tables[i]; i++ ) + xsdt->entry[i+1] = secondary_tables[i]; + xsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint64_t); + offset += align16(xsdt->header.length); set_checksum(xsdt, offsetof(struct acpi_header, checksum), xsdt->header.length); rsdt = (struct acpi_20_rsdt *)&buf[offset]; - memcpy(rsdt, &Rsdt, sizeof(struct acpi_20_rsdt)); - inc_offset(sizeof(struct acpi_20_rsdt)); + memcpy(rsdt, &Rsdt, sizeof(struct acpi_header)); rsdt->entry[0] = (unsigned long)fadt; - rsdt->header.length = sizeof(struct acpi_header) + sizeof(uint32_t); - if ( requires_madt ) - { - rsdt->entry[1] = (unsigned long)madt; - rsdt->header.length += sizeof(uint32_t); - } + for ( i = 0; secondary_tables[i]; i++ ) + rsdt->entry[i+1] = secondary_tables[i]; + rsdt->header.length = sizeof(struct acpi_header) + (i+1)*sizeof(uint32_t); + offset += align16(rsdt->header.length); set_checksum(rsdt, offsetof(struct acpi_header, checksum), rsdt->header.length); rsdp = (struct acpi_20_rsdp *)&buf[offset]; memcpy(rsdp, &Rsdp, sizeof(struct acpi_20_rsdp)); - inc_offset(sizeof(struct acpi_20_rsdp)); + offset += align16(sizeof(struct acpi_20_rsdp)); rsdp->rsdt_address = (unsigned long)rsdt; rsdp->xsdt_address = (unsigned long)xsdt; set_checksum(rsdp, @@ -190,8 +230,6 @@ int acpi_build_tables(uint8_t *buf) offsetof(struct acpi_20_rsdp, extended_checksum), sizeof(struct acpi_20_rsdp)); -#undef inc_offset - return offset; } diff --git a/tools/firmware/hvmloader/acpi_ssdt_tpm.asl b/tools/firmware/hvmloader/acpi/ssdt_tpm.asl similarity index 100% rename from tools/firmware/hvmloader/acpi_ssdt_tpm.asl rename to tools/firmware/hvmloader/acpi/ssdt_tpm.asl diff --git a/tools/firmware/hvmloader/acpi_ssdt_tpm.h b/tools/firmware/hvmloader/acpi/ssdt_tpm.h similarity index 100% rename from tools/firmware/hvmloader/acpi_ssdt_tpm.h rename to tools/firmware/hvmloader/acpi/ssdt_tpm.h diff --git a/tools/firmware/hvmloader/acpi_utils.c b/tools/firmware/hvmloader/acpi_utils.c deleted file mode 100644 index 5fd9847d4e..0000000000 --- a/tools/firmware/hvmloader/acpi_utils.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Commonly used ACPI utility functions. - * Probing for devices and writing SSDT entries into XSDT and RSDT tables. - * - * Yu Ke, ke.yu@intel.com - * Copyright (c) 2005, Intel Corporation. - * Copyright (c) 2006, IBM Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - */ - -#include "acpi/acpi2_0.h" -#include "acpi_utils.h" -#include "util.h" -#include - -static int acpi_rsdt_add_entry_pointer(unsigned char *acpi_start, - unsigned char *entry); -static int acpi_xsdt_add_entry_pointer(unsigned char *acpi_start, - unsigned char *entry); -static unsigned char *acpi_xsdt_add_entry(unsigned char *acpi_start, - unsigned char **freemem, - unsigned char *limit, - unsigned char *table, - unsigned int table_size); - -void set_checksum(void *start, int checksum_offset, int len) -{ - unsigned char sum = 0; - unsigned char *ptr; - - ptr = start; - ptr[checksum_offset] = 0; - while ( len-- ) - sum += *ptr++; - - ptr = start; - ptr[checksum_offset] = -sum; -} - - -#include "acpi_ssdt_tpm.h" -static void acpi_tpm_tis_probe(unsigned char *acpi_start, - unsigned char **freemem, - unsigned char *limit) -{ - unsigned char *addr; - ACPI_2_0_TCPA_CLIENT *tcpa; - /* check TPM_DID, TPM_VID, TPM_RID in ioemu/hw/tpm_tis.c */ - uint16_t tis_did_vid_rid[] = {0x0001, 0x0001, 0x0001}; - static const ACPI_2_0_TCPA_CLIENT Tcpa = { - .header = { - .signature = ACPI_2_0_TCPA_SIGNATURE, - .length = sizeof(ACPI_2_0_TCPA_CLIENT), - .revision = ACPI_2_0_TCPA_REVISION, - .oem_id = {'I', 'B', 'M', ' ', ' ', ' '}, - .oem_table_id = ASCII64(' ', ' ', ' ', ' ', ' ', 'x', 'e', 'n'), - .oem_revision = 1, - .creator_id = ASCII32('I', 'B', 'M', ' '), - .creator_revision = 1, - } - }; - - /* probe for TIS interface ... */ - if ( memcmp((char *)(0xFED40000 + 0xF00), - tis_did_vid_rid, - sizeof(tis_did_vid_rid)) != 0 ) - return; - - printf("TIS is available\n"); - addr = acpi_xsdt_add_entry(acpi_start, freemem, limit, - AmlCode_TPM, sizeof(AmlCode_TPM)); - if ( addr == NULL ) - return; - - /* legacy systems need an RSDT entry */ - if ( acpi_rsdt_add_entry_pointer(acpi_start, addr) != 1 ) - return; - - /* add ACPI TCPA table */ - addr = acpi_xsdt_add_entry(acpi_start, freemem, limit, - (unsigned char *)&Tcpa, - sizeof(Tcpa)); - if ( addr == NULL ) - return; - - tcpa = (ACPI_2_0_TCPA_CLIENT *)addr; - tcpa->LASA = e820_malloc( - ACPI_2_0_TCPA_LAML_SIZE, E820_RESERVED, (uint32_t)~0); - if ( tcpa->LASA ) - { - tcpa->LAML = ACPI_2_0_TCPA_LAML_SIZE; - memset((char *)(unsigned long)tcpa->LASA, - 0x0, - tcpa->LAML); - set_checksum(tcpa, - FIELD_OFFSET(struct acpi_header, checksum), - tcpa->header.length); - } - - if ( acpi_rsdt_add_entry_pointer(acpi_start, addr) != 1 ) - return; -} - - -/* - * Call functions that probe for devices and have them register their - * SSDT entries with the XSDT and RSDT tables. - */ -void acpi_update(unsigned char *acpi_start, - unsigned long acpi_size, - unsigned char *limit, - unsigned char **freemem) -{ - acpi_tpm_tis_probe(acpi_start, freemem, limit); -} - - -/* - * Search for the RSDP in memory below the BIOS - */ -struct acpi_20_rsdp *acpi_rsdp_get(unsigned char *acpi_start) -{ - int offset = 0; - int found = 0; - static int displayed = 0; - struct acpi_20_rsdp *rsdp; - - while ( &acpi_start[offset] < (unsigned char *)0xf0000 ) - { - rsdp = (struct acpi_20_rsdp *)&acpi_start[offset]; - if ( rsdp->signature == ACPI_2_0_RSDP_SIGNATURE ) - { - found = 1; - break; - } - offset += 0x10; - } - - if ( !found ) - rsdp = NULL; - - if ( !displayed ) - { - if ( rsdp ) - printf("Found RSDP at %lx\n",(long)rsdp); - else - printf("ERROR: RSDP was not found\n"); - displayed = 1; - } - - return rsdp; -} - - -struct acpi_20_rsdt *acpi_rsdt_get(unsigned char *acpi_start) -{ - struct acpi_20_rsdp *rsdp; - struct acpi_20_rsdt *rsdt; - - rsdp = acpi_rsdp_get(acpi_start); - if (!rsdp) - return NULL; - - rsdt = (struct acpi_20_rsdt *) - (acpi_start + rsdp->rsdt_address - ACPI_PHYSICAL_ADDRESS); - if ( rsdt->header.signature != ACPI_2_0_RSDT_SIGNATURE ) - { - printf("Bad RSDT signature\n"); - return NULL; - } - - return rsdt; -} - -/* - * Add an entry to the RSDT table given the pointer to the entry. - */ -static int acpi_rsdt_add_entry_pointer(unsigned char *acpi_start, - unsigned char *entry) -{ - struct acpi_20_rsdt *rsdt = acpi_rsdt_get(acpi_start); - int found = 0; - int i = 0; - - /* Find an empty slot in the RSDT table. */ - while ( i < ACPI_MAX_NUM_TABLES ) - { - if ( rsdt->entry[i] == 0 ) - { - found = 1; - break; - } - i++; - } - - if ( found ) - { - rsdt->entry[i] = (uint64_t)(unsigned long)entry; - rsdt->header.length = - sizeof(struct acpi_header) + - (i + 1) * sizeof(uint64_t); - set_checksum(rsdt, - FIELD_OFFSET(struct acpi_header, checksum), - rsdt->header.length); - } - - return found; -} - -/* Get the XSDT table. */ -struct acpi_20_xsdt *acpi_xsdt_get(unsigned char *acpi_start) -{ - struct acpi_20_rsdp *rsdp; - struct acpi_20_xsdt *xsdt; - - rsdp = acpi_rsdp_get(acpi_start); - if (!rsdp) - return NULL; - - xsdt = (struct acpi_20_xsdt *) - (acpi_start + rsdp->xsdt_address - ACPI_PHYSICAL_ADDRESS); - if ( xsdt->header.signature != ACPI_2_0_XSDT_SIGNATURE ) - { - printf("Bad XSDT signature\n"); - return NULL; - } - return xsdt; -} - -/* - * Add an entry to the XSDT table given the pointer to the entry. - */ -static int acpi_xsdt_add_entry_pointer(unsigned char *acpi_start, - unsigned char *entry) -{ - struct acpi_20_xsdt *xsdt = acpi_xsdt_get(acpi_start); - int found = 0; - int i = 0; - - /* Find an empty slot in the XSDT table. */ - while ( i < ACPI_MAX_NUM_TABLES ) - { - if ( xsdt->entry[i] == 0 ) - { - found = 1; - break; - } - i++; - } - - if ( found ) - { - xsdt->entry[i] = (uint64_t)(unsigned long)entry; - xsdt->header.length = - sizeof(struct acpi_header) + - (i + 1) * sizeof(uint64_t); - set_checksum(xsdt, - FIELD_OFFSET(struct acpi_header, checksum), - xsdt->header.length); - } - - return found; -} - -/* - add an entry to the xdst table entry pointers - copy the given ssdt data to the current available memory at - freemem, if it does not exceed the limit - */ -static unsigned char *acpi_xsdt_add_entry(unsigned char *acpi_start, - unsigned char **freemem, - unsigned char *limit, - unsigned char *table, - unsigned int table_size) -{ - struct acpi_20_xsdt *xsdt = acpi_xsdt_get(acpi_start); - int found = 0, i = 0; - unsigned char *addr = NULL; - - /* Check for an empty slot in the Xsdt table. */ - while ( i < ACPI_MAX_NUM_TABLES ) - { - if ( xsdt->entry[i] == 0 ) - { - found = 1; - break; - } - i++; - } - - if ( found ) - { - /* memory below hard limit ? */ - if ( (*freemem + table_size) <= limit ) - { - addr = *freemem; - memcpy(addr, table, table_size); - printf("Copied dyn. ACPI entry to %lx\n",(long)addr); - *freemem += ((table_size + 0xf) & ~0xf); - - acpi_xsdt_add_entry_pointer(acpi_start, addr); - } - } - - return addr; -} diff --git a/tools/firmware/hvmloader/acpi_utils.h b/tools/firmware/hvmloader/acpi_utils.h deleted file mode 100644 index 814fa3229d..0000000000 --- a/tools/firmware/hvmloader/acpi_utils.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Commonly used ACPI utility functions. - * - * Yu Ke, ke.yu@intel.com - * Copyright (c) 2005, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - */ -#ifndef ACPI_UTILS_H -#define ACPI_UTILS_H - -#define FIELD_OFFSET(TYPE,Field) ((unsigned int)(&(((TYPE *) 0)->Field))) - -#define NULL ((void*)0) - -void set_checksum(void *start, int checksum_offset, int len); -void acpi_update(unsigned char *acpi_start, - unsigned long acpi_size, - unsigned char *limit, - unsigned char **freemem); - -struct acpi_20_rsdt *acpi_rsdt_get(unsigned char *acpi_start); -struct acpi_20_xsdt *acpi_xsdt_get(unsigned char *acpi_start); - -#endif diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c index 66c113ec7c..b7729ed85d 100644 --- a/tools/firmware/hvmloader/hvmloader.c +++ b/tools/firmware/hvmloader/hvmloader.c @@ -23,7 +23,6 @@ #include "acpi/acpi2_0.h" /* for ACPI_PHYSICAL_ADDRESS */ #include "hypercall.h" #include "util.h" -#include "acpi_utils.h" #include "smbios.h" #include "config.h" #include "apic_regs.h" @@ -283,7 +282,6 @@ static void pci_setup(void) int main(void) { int acpi_sz; - uint8_t *freemem; printf("HVM Loader\n"); @@ -318,12 +316,7 @@ int main(void) { printf("Loading ACPI ...\n"); acpi_sz = acpi_build_tables((uint8_t *)ACPI_PHYSICAL_ADDRESS); - freemem = (uint8_t *)ACPI_PHYSICAL_ADDRESS + acpi_sz; - ASSERT(freemem <= (uint8_t *)0xF0000); - acpi_update((unsigned char *)ACPI_PHYSICAL_ADDRESS, - freemem - (uint8_t *)ACPI_PHYSICAL_ADDRESS, - (unsigned char *)0xF0000, - &freemem); + ASSERT((ACPI_PHYSICAL_ADDRESS + acpi_sz) <= 0xF0000); } if ( check_amd() ) diff --git a/tools/firmware/hvmloader/mp_tables.c b/tools/firmware/hvmloader/mp_tables.c index 9a1238e51a..f763d77f6b 100644 --- a/tools/firmware/hvmloader/mp_tables.c +++ b/tools/firmware/hvmloader/mp_tables.c @@ -28,7 +28,6 @@ * Place - Suite 330, Boston, MA 02111-1307 USA. */ -#include #include "config.h" /* FIXME find a header that already has types defined!!! */ diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h index 4b2f874ab3..9dac8b5343 100644 --- a/tools/firmware/hvmloader/util.h +++ b/tools/firmware/hvmloader/util.h @@ -6,6 +6,9 @@ #undef offsetof #define offsetof(t, m) ((unsigned long)&((t *)0)->m) +#undef NULL +#define NULL ((void*)0) + extern void __assert_failed(char *assertion, char *file, int line) __attribute__((noreturn)); #define ASSERT(p) \ From 07d94e438d14ce03fcb4b24ddca596a127cf5442 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 28 Nov 2006 16:22:22 +0000 Subject: [PATCH 019/282] Allow the C bindings to be more permissive when a structure is missing some entries. Complaining is just slowing development down when the server and clients get out of sync. Signed-off-by: Ewan Mellor --- tools/libxen/src/xen_common.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/libxen/src/xen_common.c b/tools/libxen/src/xen_common.c index bd370bb257..50b8e377e0 100644 --- a/tools/libxen/src/xen_common.c +++ b/tools/libxen/src/xen_common.c @@ -35,6 +35,14 @@ #include "xen_string_string_map.h" +/* + * Whether to ignore missing structure entries. This is not something we + * want to do, once the API has stabilised, as it indicates that the server is + * broken, but at the moment, complaining is just slowing development down. + */ +#define PERMISSIVE 1 + + static xmlXPathCompExprPtr responsePath = NULL; static xmlXPathCompExprPtr faultPath = NULL; @@ -756,6 +764,7 @@ static void parse_into(xen_session *s, xmlNode *value_node, cur = cur->next; } +#if !PERMISSIVE /* Check that we've filled all fields. */ for (size_t i = 0; i < member_count; i++) { @@ -780,6 +789,7 @@ static void parse_into(xen_session *s, xmlNode *value_node, return; } } +#endif free(checklist); ((void **)value)[slot] = result; From caf550ed590ec2501bac755819ce61e17c1ca46c Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 28 Nov 2006 16:23:05 +0000 Subject: [PATCH 020/282] Dummy implementation of get_platform_keymap, so that the API layer doesn't complain. This is going to change soon, I expect. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 958c5cf8f8..945cc3c3ca 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1715,6 +1715,8 @@ class XendDomainInfo: return '' # TODO def get_platform_std_vga(self): return False + def get_platform_keymap(self): + return '' def get_platform_serial(self): return '' # TODO def get_platform_localtime(self): From 0dc1af83bf422a6939bbae68a739a2de6f885c47 Mon Sep 17 00:00:00 2001 From: "jfehlig@jfehlig2.provo.novell.com" Date: Wed, 22 Nov 2006 14:25:07 -0700 Subject: [PATCH 021/282] Add libxen to overall xen build via a config option in Config.mk. Signed-off-by: Jim Fehlig --- Config.mk | 1 + tools/Makefile | 1 + tools/libxen/Makefile | 44 +++++++++++++++++++++++++++++++++++++------ 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Config.mk b/Config.mk index 4cd113d905..364c7231c4 100644 --- a/Config.mk +++ b/Config.mk @@ -71,5 +71,6 @@ ACM_DEFAULT_SECURITY_POLICY ?= ACM_NULL_POLICY XENSTAT_XENTOP ?= y VTPM_TOOLS ?= n +LIBXENAPI_BINDINGS ?= n -include $(XEN_ROOT)/.config diff --git a/tools/Makefile b/tools/Makefile index fa9d63da16..0eae0edff5 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -19,6 +19,7 @@ SUBDIRS-y += xenstat SUBDIRS-y += libaio SUBDIRS-y += blktap SUBDIRS-y += libfsimage +SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen # These don't cross-compile ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH)) diff --git a/tools/libxen/Makefile b/tools/libxen/Makefile index 88755ab6dc..c944b95215 100644 --- a/tools/libxen/Makefile +++ b/tools/libxen/Makefile @@ -15,23 +15,55 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Rules.mk + +MAJOR = 0.1 +MINOR = 0 CFLAGS = -Iinclude \ - $(shell xml2-config --cflags) \ + $(shell xml2-config --cflags) \ $(shell curl-config --cflags) \ -W -Wall -Wmissing-prototypes -Werror -std=c99 -O2 -fPIC LDFLAGS = $(shell xml2-config --libs) \ $(shell curl-config --libs) -test/test_bindings: test/test_bindings.o src/libxen.so - $(CC) $(LDFLAGS) -o $@ $< -L src -lxen +LIBXENAPI_HDRS = $(wildcard include/*.h) +LIBXENAPI_OBJS = $(patsubst %.c, %.o, $(wildcard src/*.c)) -src/libxen.so: $(patsubst %.c, %.o, $(wildcard src/*.c)) - $(CC) -shared -o $@ $^ + +.PHONY: all +all: libxenapi.so libxenapi.a + +libxenapi.so: libxenapi.so.$(MAJOR) + ln -sf $< $@ + +libxenapi.so.$(MAJOR): libxenapi.so.$(MAJOR).$(MINOR) + ln -sf $< $@ + +libxenapi.so.$(MAJOR).$(MINOR): $(LIBXENAPI_OBJS) + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenapi.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ + +libxenapi.a: $(LIBXENAPI_OBJS) + $(AR) rcs libxenapi.a $^ + + +.PHONY: install +install: all + $(INSTALL_DIR) -p $(DESTDIR)/usr/include/xen/api + $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR) + $(INSTALL_PROG) libxenapi.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR) + ln -sf libxenapi.so.$(MAJOR).$(MINOR) $(DESTDIR)/usr/$(LIBDIR)/libxenapi.so.$(MAJOR) + ln -sf libxenapi.so.$(MAJOR) $(DESTDIR)/usr/$(LIBDIR)/libxenapi.so + $(INSTALL_DATA) libxenapi.a $(DESTDIR)/usr/$(LIBDIR) + for i in $(LIBXENAPI_HDRS); do \ + $(INSTALL_DATA) $$i $(DESTDIR)/usr/include/xen/api; \ + done .PHONY: clean clean: rm -f `find -name *.o` - rm -f src/libxen.so + rm -f libxenapi.so* + rm -f libxenapi.a rm -f test/test_bindings From cee7ce97f7cf83521db30e83749c0c24ccd1fd36 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 28 Nov 2006 16:41:45 +0000 Subject: [PATCH 022/282] Clean up the DMADOM physical upper limit handling to properly honour settings in config.h. Set the upper limit for DMADOM and swiotlb allocations to be 30 bits (1G) instead of 31 bits, to allow the b44 NIC driver to work. Signed-off-by: Stephen Tweedie --- linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c | 4 ++-- xen/common/memory.c | 4 ++-- xen/include/asm-ia64/config.h | 4 +++- xen/include/asm-x86/config.h | 4 +++- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c b/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c index b100261073..be749217b1 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c @@ -47,8 +47,8 @@ EXPORT_SYMBOL(swiotlb); */ #define IO_TLB_SHIFT 11 -/* Width of DMA addresses in the IO TLB. 31 bits is an aacraid limitation. */ -#define IO_TLB_DMA_BITS 31 +/* Width of DMA addresses in the IO TLB. 30 bits is a b44 limitation. */ +#define IO_TLB_DMA_BITS 30 static int swiotlb_force; static char *iotlb_virt_start; diff --git a/xen/common/memory.c b/xen/common/memory.c index 33ead8e259..db7e9153f2 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -328,7 +328,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) (exch.out.address_bits < (get_order_from_pages(max_page) + PAGE_SHIFT)) ) { - if ( exch.out.address_bits < 31 ) + if ( exch.out.address_bits < MAX_DMADOM_BITS ) { rc = -ENOMEM; goto fail_early; @@ -541,7 +541,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) (reservation.address_bits < (get_order_from_pages(max_page) + PAGE_SHIFT)) ) { - if ( reservation.address_bits < 31 ) + if ( reservation.address_bits < MAX_DMADOM_BITS ) return start_extent; args.memflags = MEMF_dma; } diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 05910e4310..5a07cd6d7a 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -41,7 +41,9 @@ #define CONFIG_IOSAPIC #define supervisor_mode_kernel (0) -#define MAX_DMADOM_PFN (0x7FFFFFFFUL >> PAGE_SHIFT) /* 31 addressable bits */ +#define MAX_DMADOM_BITS 30 +#define MAX_DMADOM_MASK ((1UL << MAX_DMADOM_BITS) - 1) +#define MAX_DMADOM_PFN (MAX_DMADOM_MASK >> PAGE_SHIFT) /* If PERFC is used, include privop maps. */ #ifdef PERF_COUNTERS diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index cca215f4b2..8dedc54a67 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -82,7 +82,9 @@ /* Debug stack is restricted to 8kB by guard pages. */ #define DEBUG_STACK_SIZE 8192 -#define MAX_DMADOM_PFN 0x7FFFFUL /* 31 addressable bits */ +#define MAX_DMADOM_BITS 30 +#define MAX_DMADOM_MASK ((1UL << MAX_DMADOM_BITS) - 1) +#define MAX_DMADOM_PFN (MAX_DMADOM_MASK >> PAGE_SHIFT) #ifndef __ASSEMBLY__ extern unsigned long _end; /* standard ELF symbol */ From f7bd1801f809ab8ab9acec9a386bfc5a43ad3bb7 Mon Sep 17 00:00:00 2001 From: "jfehlig@jfehlig2.provo.novell.com" Date: Tue, 14 Nov 2006 15:36:41 -0700 Subject: [PATCH 023/282] Fix casing of various functions in XendAPI class. Signed-off-by: Jim Fehlig --- tools/python/xen/xend/XendAPI.py | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 1a4cc1efc7..669ffe2bc4 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -327,7 +327,7 @@ class XendAPI: # wrap validators around readable class attributes for attr_name in ro_attrs + rw_attrs + self.Base_attr_ro: - getter_name = '%s_get_%s' % (cls.lower(), attr_name.lower()) + getter_name = '%s_get_%s' % (cls.lower(), attr_name) try: getter = getattr(XendAPI, getter_name) for validator in validators: @@ -340,7 +340,7 @@ class XendAPI: # wrap validators around writable class attrributes for attr_name in rw_attrs + self.Base_attr_rw: - setter_name = '%s_set_%s' % (cls.lower(), attr_name.lower()) + setter_name = '%s_set_%s' % (cls.lower(), attr_name) try: setter = getattr(XendAPI, setter_name) for validator in validators: @@ -353,7 +353,7 @@ class XendAPI: # wrap validators around methods for method_name in methods + self.Base_methods: - method_full_name = '%s_%s' % (cls.lower(),method_name.lower()) + method_full_name = '%s_%s' % (cls.lower(), method_name) try: method = getattr(XendAPI, method_full_name) for validator in validators: @@ -366,7 +366,7 @@ class XendAPI: # wrap validators around class functions for func_name in funcs + self.Base_funcs: - func_full_name = '%s_%s' % (cls.lower(), func_name.lower()) + func_full_name = '%s_%s' % (cls.lower(), func_name) try: method = getattr(XendAPI, func_full_name) method = session_required(method) @@ -411,7 +411,7 @@ class XendAPI: record = {'this_host': XendNode.instance().uuid, 'this_user': auth_manager().get_user(session)} return xen_api_success(record) - def session_to_xml(self, session): + def session_to_XML(self, session): return xen_api_todo() # attributes (ro) @@ -536,7 +536,7 @@ class XendAPI: 'features': node.get_host_cpu_features(host_cpu_ref), 'utilisation': node.get_host_cpu_load(host_cpu_ref)} return xen_api_success(record) - def host_cpu_to_xml(self, session, host_cpu_ref): + def host_cpu_to_XML(self, session, host_cpu_ref): return xen_api_todo() # class methods @@ -586,7 +586,7 @@ class XendAPI: 'VCPUs_policy', 'VCPUs_params', 'VCPUs_features_force_on', - 'VCPUS_features_force_off', + 'VCPUs_features_force_off', 'actions_after_shutdown', 'actions_after_reboot', 'actions_after_suspend', @@ -848,19 +848,19 @@ class XendAPI: dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_vcpus_policy(self, session, vm_ref): + def vm_set_VCPUs_policy(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_vcpus_params(self, session, vm_ref): + def vm_set_VCPUs_params(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_vcpus_features_force_on(self, session, vm_ref): + def vm_set_VCPUs_features_force_on(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_vcpus_features_force_off(self, session, vm_ref): + def vm_set_VCPUs_features_force_off(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() @@ -950,7 +950,7 @@ class XendAPI: return xen_api_success(domuuid) # object methods - def vm_to_xml(self, session, vm_ref): + def vm_to_XML(self, session, vm_ref): return xen_api_todo() def vm_get_record(self, session, vm_ref): @@ -1092,11 +1092,11 @@ class XendAPI: return xen_api_success(vbd_ref) # attributes (rw) - def vbd_get_vm(self, session, vbd_ref): + def vbd_get_VM(self, session, vbd_ref): xendom = XendDomain.instance() return xen_api_success(xendom.get_dev_property('vbd', vbd_ref, 'VM')) - def vbd_get_vdi(self, session, vbd_ref): + def vbd_get_VDI(self, session, vbd_ref): return xen_api_todo() def vbd_get_device(self, session, vbd_ref): @@ -1218,7 +1218,7 @@ class XendAPI: image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.name_description) - def vdi_get_sr(self, session, vdi_ref): + def vdi_get_SR(self, session, vdi_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.uuid) @@ -1249,7 +1249,7 @@ class XendAPI: image.name_description = value return xen_api_success_void() - def vdi_set_sr(self, session, vdi_ref, value): + def vdi_set_SR(self, session, vdi_ref, value): return xen_api_error(XEND_ERROR_UNSUPPORTED) def vdi_set_virtual_size(self, session, vdi_ref, value): @@ -1269,7 +1269,7 @@ class XendAPI: sr.destroy_image(vdi_ref) return xen_api_success_void() - def vdi_to_xml(self, session, vdi_ref): + def vdi_to_XML(self, session, vdi_ref): return xen_api_todo() def vdi_get_record(self, session, vdi_ref): @@ -1451,7 +1451,7 @@ class XendAPI: def sr_destroy(self, session, sr_ref): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def sr_to_xml(self, session, sr_ref): + def sr_to_XML(self, session, sr_ref): return xen_api_todo() def sr_get_record(self, session, sr_ref): @@ -1469,7 +1469,7 @@ class XendAPI: }) # Attribute acceess - def sr_get_vdis(self, session, sr_ref): + def sr_get_VDIs(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.list_images()) From 9b0990ce13e40678258afe75816cd5c21a1dbea4 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 15 Nov 2006 11:34:31 -0700 Subject: [PATCH 024/282] [IA64] MCA support - fix timer issue, log size issue, and limit logs to dom0 Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- linux-2.6-xen-sparse/include/asm-ia64/sal.h | 8 ++++---- xen/arch/ia64/linux-xen/mca.c | 10 ++++++++++ xen/arch/ia64/xen/fw_emul.c | 7 +++++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/linux-2.6-xen-sparse/include/asm-ia64/sal.h b/linux-2.6-xen-sparse/include/asm-ia64/sal.h index 0cda1c410b..9439b49d8b 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/sal.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/sal.h @@ -699,16 +699,16 @@ ia64_sal_get_state_info (u64 sal_info_type, u64 *sal_info) struct ia64_sal_retval isrv; #ifdef CONFIG_XEN if (is_running_on_xen()) { - struct xencomm_mini xc_area[2]; - int nbr_area = 2; struct xencomm_handle *desc; - if (xencomm_create_mini(xc_area, &nbr_area, sal_info, - ia64_sal_get_state_info_size(sal_info_type), &desc)) + if (xencomm_create(sal_info, + ia64_sal_get_state_info_size(sal_info_type), + &desc, GFP_KERNEL)) return 0; SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, desc, 0, 0, 0, 0); + xencomm_free(desc); } else #endif SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0, diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c index 261e7a0174..2d221cd7f9 100644 --- a/xen/arch/ia64/linux-xen/mca.c +++ b/xen/arch/ia64/linux-xen/mca.c @@ -118,6 +118,12 @@ extern void setup_vector (unsigned int vec, struct irqaction *action); static ia64_mc_info_t ia64_mc_info; +#ifdef XEN +#define jiffies NOW() +#undef HZ +#define HZ 1000000000UL +#endif + #define MAX_CPE_POLL_INTERVAL (15*60*HZ) /* 15 minutes */ #define MIN_CPE_POLL_INTERVAL (2*60*HZ) /* 2 minutes */ #define CMC_POLL_INTERVAL (1*60*HZ) /* 1 minute */ @@ -1388,7 +1394,11 @@ static irqreturn_t ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) { static int start_count = -1; +#ifdef XEN + static unsigned long poll_time = MIN_CPE_POLL_INTERVAL; +#else static int poll_time = MIN_CPE_POLL_INTERVAL; +#endif unsigned int cpuid; cpuid = smp_processor_id(); diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c index ff024147a8..6a37f051c4 100644 --- a/xen/arch/ia64/xen/fw_emul.c +++ b/xen/arch/ia64/xen/fw_emul.c @@ -205,7 +205,7 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, } break; case SAL_GET_STATE_INFO: - { + if (current->domain == dom0) { sal_queue_entry_t *e; unsigned long flags; struct smp_call_args_t arg; @@ -274,13 +274,16 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, spin_unlock_irqrestore(&sal_queue_lock, flags); xfree(e); } + } else { + status = IA64_SAL_NO_INFORMATION_AVAILABLE; + r9 = 0; } break; case SAL_GET_STATE_INFO_SIZE: r9 = ia64_sal_get_state_info_size(in1); break; case SAL_CLEAR_STATE_INFO: - { + if (current->domain == dom0) { sal_queue_entry_t *e; unsigned long flags; struct smp_call_args_t arg; From 7e0011c3c577994532f912f4ef32587aed3bb0e2 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 15 Nov 2006 11:55:04 -0700 Subject: [PATCH 025/282] [IA64] MCA support - Disable CPE interrupt mode for dom0 This patch disables CPE interupt mode for dom0. In current MCA implementaion, CPE interrupts do not notify to dom0. The dom0 is expected to get error logs in polling mode. Therefore I modified the ACPI table to disable CPE interrupt mode in before the address of it is passed through to dom0. I think that there is no problem because the initialization of ACPI is completed by the passed time even if this modification is added. Signed-off-by: Yutaka Ezaki Signed-off-by: Masaki Kanno Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/xen/dom_fw.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/xen/dom_fw.c b/xen/arch/ia64/xen/dom_fw.c index b2c3f8ef6a..856a665bcd 100644 --- a/xen/arch/ia64/xen/dom_fw.c +++ b/xen/arch/ia64/xen/dom_fw.c @@ -240,6 +240,23 @@ acpi_update_lsapic (acpi_table_entry_header *header, const unsigned long end) return 0; } +static int __init +acpi_patch_plat_int_src ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_plat_int_src *plintsrc; + + plintsrc = (struct acpi_table_plat_int_src *)header; + if (!plintsrc) + return -EINVAL; + + if (plintsrc->type == ACPI_INTERRUPT_CPEI) { + printk("ACPI_INTERRUPT_CPEI disabled for Domain0\n"); + plintsrc->type = -1; + } + return 0; +} + static u8 generate_acpi_checksum(void *tbl, unsigned long len) { @@ -271,7 +288,11 @@ static void touch_acpi_table(void) { lsapic_nbr = 0; if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_update_lsapic, 0) < 0) - printk("Error parsing MADT - no LAPIC entires\n"); + printk("Error parsing MADT - no LAPIC entries\n"); + if (acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, + acpi_patch_plat_int_src, 0) < 0) + printk("Error parsing MADT - no PLAT_INT_SRC entries\n"); + acpi_table_parse(ACPI_APIC, acpi_update_madt_checksum); return; From ad0a6d39f2f442244d7b8e5b5efa4c0823822128 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 15 Nov 2006 12:15:34 -0700 Subject: [PATCH 026/282] [IA64] Remove unecessary MCA boot messages Signed-off-by: Alex Williamson --- xen/arch/ia64/linux-xen/mca.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c index 2d221cd7f9..06b9b27efb 100644 --- a/xen/arch/ia64/linux-xen/mca.c +++ b/xen/arch/ia64/linux-xen/mca.c @@ -1842,8 +1842,8 @@ ia64_mca_late_init(void) init_timer(&cmc_poll_timer); cmc_poll_timer.function = ia64_mca_cmc_poll; #else - init_timer(&cmc_poll_timer, ia64_mca_cmc_poll, NULL, smp_processor_id()); - printk("INIT_TIMER(cmc_poll_timer): on cpu%d\n", smp_processor_id()); + init_timer(&cmc_poll_timer, ia64_mca_cmc_poll, + NULL, smp_processor_id()); #endif /* Unmask/enable the vector */ @@ -1863,8 +1863,8 @@ ia64_mca_late_init(void) init_timer(&cpe_poll_timer); cpe_poll_timer.function = ia64_mca_cpe_poll; #else - init_timer(&cpe_poll_timer, ia64_mca_cpe_poll, NULL, smp_processor_id()); - printk("INIT_TIMER(cpe_poll_timer): on cpu%d\n", smp_processor_id()); + init_timer(&cpe_poll_timer, ia64_mca_cpe_poll, + NULL,smp_processor_id()); #endif { From 3801b5969035f0f0316ec765b9e782e113a3f88b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 20 Nov 2006 09:39:46 -0700 Subject: [PATCH 027/282] [IA64] counter part of 12385:bfe3f8f35e87 xen-unstable.hg. return -ENOSYS for undefined sub-functions. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/hypercall.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index effa38ef99..d04ed8b11d 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -453,7 +453,7 @@ static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) } default: - ret = -EINVAL; + ret = -ENOSYS; break; } @@ -479,7 +479,7 @@ static long register_guest_callback(struct callback_register *reg) break; default: - ret = -EINVAL; + ret = -ENOSYS; break; } @@ -488,7 +488,7 @@ static long register_guest_callback(struct callback_register *reg) static long unregister_guest_callback(struct callback_unregister *unreg) { - return -EINVAL ; + return -EINVAL; } /* First time to add callback to xen/ia64, so let's just stick to @@ -525,7 +525,7 @@ static long do_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg) break; default: - ret = -EINVAL; + ret = -ENOSYS; break; } From 68eca07ccada163f7f01680483bce4780c434fdc Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 20 Nov 2006 10:06:18 -0700 Subject: [PATCH 028/282] [IA64] eliminate redundant wakeup logic Signed-off-by: Anthony Xu --- xen/arch/ia64/vmx/vlsapic.c | 11 ----------- xen/include/asm-ia64/vmx_platform.h | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/xen/arch/ia64/vmx/vlsapic.c b/xen/arch/ia64/vmx/vlsapic.c index 3a6d85a36a..5e4ccbd8fd 100644 --- a/xen/arch/ia64/vmx/vlsapic.c +++ b/xen/arch/ia64/vmx/vlsapic.c @@ -677,14 +677,3 @@ void vmx_vioapic_set_irq(struct domain *d, int irq, int level) spin_unlock_irqrestore(&d->arch.arch_vmx.virq_assist_lock, flags); } -int vmx_vlapic_set_irq(VCPU *v, uint8_t vec, uint8_t trig) -{ - int ret; - int running = test_bit(_VCPUF_running, &v->vcpu_flags); - - ret = vmx_vcpu_pend_interrupt(v, vec); - vcpu_unblock(v); - if (running) - smp_send_event_check_cpu(v->processor); - return ret; -} diff --git a/xen/include/asm-ia64/vmx_platform.h b/xen/include/asm-ia64/vmx_platform.h index 878961ef04..7239fd1793 100644 --- a/xen/include/asm-ia64/vmx_platform.h +++ b/xen/include/asm-ia64/vmx_platform.h @@ -56,10 +56,10 @@ extern uint64_t dummy_tmr[]; #define VLAPIC_ID(l) (uint16_t)(((l)->vcpu->arch.privregs->lid) >> 16) #define VLAPIC_IRR(l) ((l)->vcpu->arch.privregs->irr[0]) struct vlapic *apic_round_robin(struct domain *d, uint8_t vector, uint32_t bitmap); -extern int vmx_vlapic_set_irq(struct vcpu *v, uint8_t vec, uint8_t trig); +extern int vmx_vcpu_pend_interrupt(struct vcpu *vcpu, uint8_t vector); static inline int vlapic_set_irq(struct vlapic *t, uint8_t vec, uint8_t trig) { - return vmx_vlapic_set_irq(t->vcpu, vec, trig); + return vmx_vcpu_pend_interrupt(t->vcpu, vec); } enum ioapic_irq_destination_types { From f9b170e324a23c5c403e2b8dc8f5a49a524b1e0f Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 20 Nov 2006 10:10:28 -0700 Subject: [PATCH 029/282] [IA64] Grantcopy added to xcom_mini for netback module This patch adds grantcopy to xcom_mini allowing netback to work as a module. Signed-off-by: Tsunehisa Doi Signed-off-by: Naoki Takayama Signed-off-by: Tomonari Horikoshi --- linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c index 5adec0c325..0453cb4437 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c @@ -93,6 +93,9 @@ xencommize_mini_grant_table_op(struct xencomm_mini *xc_area, int *nbr_area, case GNTTABOP_transfer: argsize = sizeof(struct gnttab_transfer); break; + case GNTTABOP_copy: + argsize = sizeof(struct gnttab_copy); + break; default: printk("%s: unknown mini grant table op %d\n", __func__, cmd); BUG(); From 758fbf680d14d7d464163c762553aae415e5f852 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 20 Nov 2006 12:14:40 -0700 Subject: [PATCH 030/282] [IA64] Fix for queueing the MCA error logs This patch fixes bugs of queueing the MCA error logs. It is necessary to queue the error log, when the MCA polling handler is called. And it is also needed to queue when cpe interrupt handler is called. Signed-off-by: Kazuhiro Suzuki --- xen/arch/ia64/linux-xen/mca.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c index 06b9b27efb..cf43c17cb8 100644 --- a/xen/arch/ia64/linux-xen/mca.c +++ b/xen/arch/ia64/linux-xen/mca.c @@ -496,9 +496,9 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs) /* Get the CPE error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE); #else + ia64_log_queue(SAL_INFO_TYPE_CPE, VIRQ_MCA_CPE); /* CPE error does not inform to dom0 but the following codes are reserved for future implementation */ -/* ia64_log_queue(SAL_INFO_TYPE_CPE, VIRQ_MCA_CPE); */ /* send_guest_vcpu_virq(dom0->vcpu[0], VIRQ_MCA_CPE); */ #endif @@ -1325,6 +1325,10 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs) #ifndef XEN ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs); +#else + IA64_MCA_DEBUG("%s: received polling vector = %#x on CPU %d\n", + __FUNCTION__, cmc_irq, smp_processor_id()); + ia64_log_queue(SAL_INFO_TYPE_CMC, VIRQ_MCA_CMC); #endif for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); @@ -1409,6 +1413,10 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) #ifndef XEN ia64_mca_cpe_int_handler(cpe_irq, arg, ptregs); +#else + IA64_MCA_DEBUG("%s: received polling vector = %#x on CPU %d\n", + __FUNCTION__, cpe_irq, smp_processor_id()); + ia64_log_queue(SAL_INFO_TYPE_CPE, VIRQ_MCA_CPE); #endif for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++); From 72c4d79ff2d81178422a9c69b6bd4623a5969d43 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 20 Nov 2006 21:10:59 -0700 Subject: [PATCH 031/282] [IA64] fix broken PAL_HALT_LIGHT xen-unstable.hg cset 12471:cf98903ebb22 changed do_block() to only pend a schedule softirq. We now need to explicitly call do_softirq() for force the schedule, otherwise we stop the hlt_timer before it does it's thing. Signed-off-by: Alex Williamson --- xen/arch/ia64/xen/hypercall.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index d04ed8b11d..ba4daba297 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -248,6 +248,8 @@ ia64_hypercall(struct pt_regs *regs) set_timer(&v->arch.hlt_timer, vcpu_get_next_timer_ns(v)); do_sched_op_compat(SCHEDOP_block, 0); + /* do_block only pends a softirq */ + do_softirq(); stop_timer(&v->arch.hlt_timer); } regs->r8 = 0; From 53df32c97490ae1a009269cb6037633ca2d312e5 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 22 Nov 2006 09:30:27 -0700 Subject: [PATCH 032/282] [IA64] New initial memory interface for HVM on ia64 Use xc_domain_memory_populate_physmap() to allocate memory and build P2M/M2P table in setup_guest(). vmx_build_physmap_table() is only used to mark IO space now. Signed-off-by: Zhang Xin --- tools/libxc/ia64/xc_ia64_hvm_build.c | 105 ++++++++++++++++++++++----- xen/arch/ia64/vmx/vmx_init.c | 66 ++--------------- 2 files changed, 90 insertions(+), 81 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_hvm_build.c b/tools/libxc/ia64/xc_ia64_hvm_build.c index a97b82af23..c39542eb12 100644 --- a/tools/libxc/ia64/xc_ia64_hvm_build.c +++ b/tools/libxc/ia64/xc_ia64_hvm_build.c @@ -546,19 +546,32 @@ add_pal_hob(void* hob_buf) return 0; } +#define GFW_PAGES (GFW_SIZE >> PAGE_SHIFT) +#define VGA_START_PAGE (VGA_IO_START >> PAGE_SHIFT) +#define VGA_END_PAGE ((VGA_IO_START + VGA_IO_SIZE) >> PAGE_SHIFT) +/* + * In this function, we will allocate memory and build P2M/M2P table for VTI + * guest. Frist, a pfn list will be initialized discontiguous, normal memory + * begins with 0, GFW memory and other three pages at their place defined in + * xen/include/public/arch-ia64.h xc_domain_memory_populate_physmap() called + * three times, to set parameter 'extent_order' to different value, this is + * convenient to allocate discontiguous memory with different size. + */ static int setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, char *image, unsigned long image_size, uint32_t vcpus, unsigned int store_evtchn, unsigned long *store_mfn) { - unsigned long page_array[3]; + xen_pfn_t *pfn_list; shared_iopage_t *sp; void *ioreq_buffer_page; - // memsize = required memsize(in configure file) + 16M + // memsize equal to normal memory size(in configure file) + 16M // dom_memsize will pass to xc_ia64_build_hob(), so must be subbed 16M unsigned long dom_memsize = ((memsize - 16) << 20); unsigned long nr_pages = (unsigned long)memsize << (20 - PAGE_SHIFT); + unsigned long normal_pages = nr_pages - GFW_PAGES; int rc; + long i, j; DECLARE_DOMCTL; // ROM size for guest firmware, ioreq page and xenstore page @@ -569,14 +582,63 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, return -1; } - rc = xc_domain_memory_increase_reservation(xc_handle, dom, nr_pages, - 0, 0, NULL); + pfn_list = malloc(nr_pages * sizeof(xen_pfn_t)); + if (pfn_list == NULL) { + PERROR("Could not allocate memory.\n"); + return -1; + } + + // Allocate pfn for normal memory + for (i = 0; i < dom_memsize >> PAGE_SHIFT; i++) + pfn_list[i] = i; + + // If normal memory > 3G. Reserve 3G ~ 4G for MMIO, GFW and others. + for (j = (MMIO_START >> PAGE_SHIFT); j < (dom_memsize >> PAGE_SHIFT); j++) + pfn_list[j] += ((1 * MEM_G) >> PAGE_SHIFT); + + // Allocate memory for VTI guest, up to VGA hole from 0xA0000-0xC0000. + rc = xc_domain_memory_populate_physmap(xc_handle, dom, + (normal_pages > VGA_START_PAGE) ? + VGA_START_PAGE : normal_pages, + 0, 0, &pfn_list[0]); + + // We're not likely to attempt to create a domain with less than + // 640k of memory, but test for completeness + if (rc == 0 && nr_pages > VGA_END_PAGE) + rc = xc_domain_memory_populate_physmap(xc_handle, dom, + normal_pages - VGA_END_PAGE, + 0, 0, &pfn_list[VGA_END_PAGE]); if (rc != 0) { - PERROR("Could not allocate memory for HVM guest.\n"); + PERROR("Could not allocate normal memory for Vti guest.\n"); + goto error_out; + } + + // We allocate additional pfn for GFW and other three pages, so + // the pfn_list is not contiguous. Due to this we must support + // old interface xc_ia64_get_pfn_list(). + // Here i = (dom_memsize >> PAGE_SHIFT) + for (j = 0; i < nr_pages - 3; i++, j++) + pfn_list[i] = (GFW_START >> PAGE_SHIFT) + j; + + rc = xc_domain_memory_populate_physmap(xc_handle, dom, GFW_PAGES, + 0, 0, &pfn_list[normal_pages]); + if (rc != 0) { + PERROR("Could not allocate GFW memory for Vti guest.\n"); + goto error_out; + } + + // Here i = (dom_memsize >> PAGE_SHIFT) + GFW_PAGES + pfn_list[i] = IO_PAGE_START >> PAGE_SHIFT; + pfn_list[i+1] = STORE_PAGE_START >> PAGE_SHIFT; + pfn_list[i+2] = BUFFER_IO_PAGE_START >> PAGE_SHIFT; + + rc = xc_domain_memory_populate_physmap(xc_handle, dom, 3, + 0, 0, &pfn_list[nr_pages - 3]); + if (rc != 0) { + PERROR("Could not allocate GFW memory for Vti guest.\n"); goto error_out; } - /* This will creates the physmap. */ domctl.u.arch_setup.flags = XEN_DOMAINSETUP_hvm_guest; domctl.u.arch_setup.bp = 0; domctl.u.arch_setup.maxmem = 0; @@ -585,7 +647,13 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, if (xc_domctl(xc_handle, &domctl)) goto error_out; - /* Load guest firmware */ + if (xc_domain_translate_gpfn_list(xc_handle, dom, nr_pages, + pfn_list, pfn_list)) { + PERROR("Could not translate addresses of HVM guest.\n"); + goto error_out; + } + + // Load guest firmware if (xc_ia64_copy_to_domain_pages(xc_handle, dom, image, (GFW_START + GFW_SIZE - image_size) >> PAGE_SHIFT, image_size >> PAGE_SHIFT)) { @@ -593,36 +661,33 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, goto error_out; } - /* Hand-off state passed to guest firmware */ + // Hand-off state passed to guest firmware if (xc_ia64_build_hob(xc_handle, dom, dom_memsize, (unsigned long)vcpus) < 0) { PERROR("Could not build hob\n"); goto error_out; } - /* Retrieve special pages like io, xenstore, etc. */ - if (xc_ia64_get_pfn_list(xc_handle, dom, page_array, - IO_PAGE_START>>PAGE_SHIFT, 3) != 3) { - PERROR("Could not get the page frame list"); - goto error_out; - } - xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, STORE_PAGE_START>>PAGE_SHIFT); xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn); - *store_mfn = page_array[1]; - sp = (shared_iopage_t *)xc_map_foreign_range(xc_handle, dom, - PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[0]); + // Retrieve special pages like io, xenstore, etc. + *store_mfn = pfn_list[nr_pages - 2]; + sp = (shared_iopage_t *)xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ | PROT_WRITE, + pfn_list[nr_pages - 3]); if (sp == 0) goto error_out; memset(sp, 0, PAGE_SIZE); munmap(sp, PAGE_SIZE); - ioreq_buffer_page = xc_map_foreign_range(xc_handle, dom, - PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[2]); + ioreq_buffer_page = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ | PROT_WRITE, + pfn_list[nr_pages - 1]); memset(ioreq_buffer_page,0,PAGE_SIZE); munmap(ioreq_buffer_page, PAGE_SIZE); + free(pfn_list); return 0; error_out: diff --git a/xen/arch/ia64/vmx/vmx_init.c b/xen/arch/ia64/vmx/vmx_init.c index 03b7af7b9c..ea6025eecc 100644 --- a/xen/arch/ia64/vmx/vmx_init.c +++ b/xen/arch/ia64/vmx/vmx_init.c @@ -359,17 +359,11 @@ static const io_range_t io_ranges[] = { {PIB_START, PIB_SIZE, GPFN_PIB}, }; -/* Reseve 1 page for shared I/O ,1 page for xenstore and 1 page for buffer I/O. */ -#define VMX_SYS_PAGES (3 + (GFW_SIZE >> PAGE_SHIFT)) -/* If we support maxmem for domVTi, we should change from tot_page to max_pages. - * #define VMX_CONFIG_PAGES(d) ((d)->max_pages - VMX_SYS_PAGES) - */ -#define VMX_CONFIG_PAGES(d) ((d)->tot_pages - VMX_SYS_PAGES) - -static void vmx_build_physmap_table(struct domain *d) +// The P2M table is built in libxc/ia64/xc_ia64_hvm_build.c @ setup_guest() +// so only mark IO memory space here +static void vmx_build_io_physmap_table(struct domain *d) { - unsigned long i, j, start, tmp, end, mfn; - struct list_head *list_ent = d->page_list.next; + unsigned long i, j; /* Mark I/O ranges */ for (i = 0; i < (sizeof(io_ranges) / sizeof(io_range_t)); i++) { @@ -379,63 +373,13 @@ static void vmx_build_physmap_table(struct domain *d) ASSIGN_writable); } - /* Map normal memory below 3G */ - end = VMX_CONFIG_PAGES(d) << PAGE_SHIFT; - tmp = end < MMIO_START ? end : MMIO_START; - for (i = 0; (i < tmp) && (list_ent != &d->page_list); i += PAGE_SIZE) { - mfn = page_to_mfn(list_entry(list_ent, struct page_info, list)); - list_ent = mfn_to_page(mfn)->list.next; - if (VGA_IO_START <= i && i < VGA_IO_START + VGA_IO_SIZE) - continue; - assign_domain_page(d, i, mfn << PAGE_SHIFT); - } - ASSERT(list_ent != &d->page_list); - - /* Map normal memory beyond 4G */ - if (unlikely(end > MMIO_START)) { - start = 4 * MEM_G; - end = start + (end - 3 * MEM_G); - for (i = start; - (i < end) && (list_ent != &d->page_list); i += PAGE_SIZE) { - mfn = page_to_mfn(list_entry(list_ent, - struct page_info, list)); - assign_domain_page(d, i, mfn << PAGE_SHIFT); - list_ent = mfn_to_page(mfn)->list.next; - } - ASSERT(list_ent != &d->page_list); - } - - /* Map guest firmware */ - for (i = GFW_START; (i < GFW_START + GFW_SIZE) && - (list_ent != &d->page_list); i += PAGE_SIZE) { - mfn = page_to_mfn(list_entry(list_ent, struct page_info, list)); - assign_domain_page(d, i, mfn << PAGE_SHIFT); - list_ent = mfn_to_page(mfn)->list.next; - } - ASSERT(list_ent != &d->page_list); - - /* Map for shared I/O page and xenstore */ - mfn = page_to_mfn(list_entry(list_ent, struct page_info, list)); - assign_domain_page(d, IO_PAGE_START, mfn << PAGE_SHIFT); - list_ent = mfn_to_page(mfn)->list.next; - ASSERT(list_ent != &d->page_list); - - mfn = page_to_mfn(list_entry(list_ent, struct page_info, list)); - assign_domain_page(d, STORE_PAGE_START, mfn << PAGE_SHIFT); - list_ent = mfn_to_page(mfn)->list.next; - ASSERT(list_ent != &d->page_list); - - mfn = page_to_mfn(list_entry(list_ent, struct page_info, list)); - assign_domain_page(d, BUFFER_IO_PAGE_START, mfn << PAGE_SHIFT); - list_ent = mfn_to_page(mfn)->list.next; - ASSERT(list_ent == &d->page_list); } void vmx_setup_platform(struct domain *d) { ASSERT(d != dom0); /* only for non-privileged vti domain */ - vmx_build_physmap_table(d); + vmx_build_io_physmap_table(d); d->arch.vmx_platform.shared_page_va = (unsigned long)__va(__gpa_to_mpa(d, IO_PAGE_START)); From d28132e9b9e137e18a8fb8a928c7e1acb0122bd4 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 22 Nov 2006 10:10:38 -0700 Subject: [PATCH 033/282] [IA64] fix paravirtualization of clone2() system call. If audit is enabled or the child process is ptraced, non-paravirtualized code path is executed. Thus paravirtualized ifs is left unmodifed so that the child process crashes after clone2(). paravirtualize ia64_ret_from_clone() to fix it. Signed-off-by: Isaku Yamahata --- linux-2.6-xen-sparse/arch/ia64/kernel/entry.S | 4 +- linux-2.6-xen-sparse/arch/ia64/xen/xenentry.S | 41 +++++++++++++++++++ .../include/asm-ia64/privop.h | 1 + .../include/asm-ia64/xen/privop.h | 1 + 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/entry.S b/linux-2.6-xen-sparse/arch/ia64/kernel/entry.S index 67738bb21d..67f37b2c53 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/entry.S +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/entry.S @@ -602,7 +602,7 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel) .ret4: br.cond.sptk ia64_leave_kernel END(ia64_strace_leave_kernel) -GLOBAL_ENTRY(ia64_ret_from_clone) +GLOBAL_ENTRY(__ia64_ret_from_clone) PT_REGS_UNWIND_INFO(0) { /* * Some versions of gas generate bad unwind info if the first instruction of a @@ -628,7 +628,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone) cmp.ne p6,p0=r2,r0 (p6) br.cond.spnt .strace_check_retval ;; // added stop bits to prevent r8 dependency -END(ia64_ret_from_clone) +END(__ia64_ret_from_clone) // fall through GLOBAL_ENTRY(ia64_ret_from_syscall) PT_REGS_UNWIND_INFO(0) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xenentry.S b/linux-2.6-xen-sparse/arch/ia64/xen/xenentry.S index bd66913f4f..aad0aac631 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xenentry.S +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xenentry.S @@ -237,6 +237,47 @@ END(xen_trace_syscall) END(ia64_trace_syscall) #endif +#ifdef CONFIG_XEN +GLOBAL_ENTRY(xen_ret_from_clone) + PT_REGS_UNWIND_INFO(0) + movl r16=running_on_xen;; + ld4 r16=[r16];; + cmp.eq p7,p0=r16,r0 +(p7) br.cond.sptk.many __ia64_ret_from_clone;; +#else +GLOBAL_ENTRY(ia64_ret_from_clone) + PT_REGS_UNWIND_INFO(0) +#endif +{ /* + * Some versions of gas generate bad unwind info if the first instruction of a + * procedure doesn't go into the first slot of a bundle. This is a workaround. + */ + nop.m 0 + nop.i 0 + /* + * We need to call schedule_tail() to complete the scheduling process. + * Called by ia64_switch_to() after do_fork()->copy_thread(). r8 contains the + * address of the previously executing task. + */ + br.call.sptk.many rp=ia64_invoke_schedule_tail +} +.ret8: + adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 + ;; + ld4 r2=[r2] + ;; + mov r8=0 + and r2=_TIF_SYSCALL_TRACEAUDIT,r2 + ;; + cmp.ne p6,p0=r2,r0 +(p6) br.cond.spnt .strace_check_retval + ;; // added stop bits to prevent r8 dependency +#ifdef CONFIG_XEN + br.cond.sptk ia64_ret_from_syscall +END(xen_ret_from_clone) +#else +END(ia64_ret_from_clone) +#endif /* * ia64_leave_syscall(): Same as ia64_leave_kernel, except that it doesn't * need to switch to bank 0 and doesn't restore the scratch registers. diff --git a/linux-2.6-xen-sparse/include/asm-ia64/privop.h b/linux-2.6-xen-sparse/include/asm-ia64/privop.h index 28c1e886c0..05935407ee 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/privop.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/privop.h @@ -49,6 +49,7 @@ #define ia64_leave_kernel __ia64_leave_kernel #define ia64_leave_syscall __ia64_leave_syscall #define ia64_trace_syscall __ia64_trace_syscall +#define ia64_ret_from_clone __ia64_ret_from_clone #define ia64_switch_to __ia64_switch_to #define ia64_pal_call_static __ia64_pal_call_static diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h index 6f3c20a8ed..a2615ca7e7 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h @@ -295,6 +295,7 @@ extern void xen_ptcga(unsigned long addr, unsigned long size); #define ia64_leave_kernel xen_leave_kernel #define ia64_leave_syscall xen_leave_syscall #define ia64_trace_syscall xen_trace_syscall +#define ia64_ret_from_clone xen_ret_from_clone #define ia64_switch_to xen_switch_to #define ia64_pal_call_static xen_pal_call_static From ffc7a87f6566d9ab5e28b088ef889152f5931bc8 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 22 Nov 2006 10:13:31 -0700 Subject: [PATCH 034/282] [IA64] fix a bug in vmx_send_assist_req() We must do_softirq() explicitly to enter scheduler If not, booting a windows guest and a linux guest at the same time will lead to a system hang. Signed-off-by: Zhang Xin --- xen/arch/ia64/vmx/vmx_support.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/xen/arch/ia64/vmx/vmx_support.c b/xen/arch/ia64/vmx/vmx_support.c index ea7e24afe8..667d983857 100644 --- a/xen/arch/ia64/vmx/vmx_support.c +++ b/xen/arch/ia64/vmx/vmx_support.c @@ -76,11 +76,6 @@ void vmx_send_assist_req(struct vcpu *v) p->state = STATE_IOREQ_READY; notify_via_xen_event_channel(v->arch.arch_vmx.xen_port); - /* - * Waiting for MMIO completion - * like the wait_on_xen_event_channel() macro like... - * but, we can't call do_softirq() at this point.. - */ for (;;) { if (p->state != STATE_IOREQ_READY && p->state != STATE_IOREQ_INPROCESS) @@ -96,6 +91,7 @@ void vmx_send_assist_req(struct vcpu *v) } raise_softirq(SCHEDULE_SOFTIRQ); + do_softirq(); mb(); } From daed959ce127b5bbd4f2dae703fb3c05331041ba Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 27 Nov 2006 09:26:15 -0700 Subject: [PATCH 035/282] [IA64] fix p2m table destruction Introduce delayed p2m table destruction Signed-off-by: Tsunehisa Doi Signed-off-by: Tomonari Horikoshi Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/domain.c | 15 +++--- xen/arch/ia64/xen/mm.c | 106 +++++++++++++++++++++++++++---------- xen/include/asm-ia64/mm.h | 3 +- 3 files changed, 87 insertions(+), 37 deletions(-) diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index ec0d415a05..3dede16491 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -462,11 +462,10 @@ fail_nomem1: void arch_domain_destroy(struct domain *d) { - BUG_ON(d->arch.mm.pgd != NULL); + mm_final_teardown(d); + if (d->shared_info != NULL) free_xenheap_pages(d->shared_info, get_order_from_shift(XSI_SHIFT)); - if (d->arch.shadow_bitmap != NULL) - xfree(d->arch.shadow_bitmap); tlb_track_destroy(d); @@ -613,14 +612,14 @@ static void relinquish_memory(struct domain *d, struct list_head *list) void domain_relinquish_resources(struct domain *d) { - /* Relinquish every page of memory. */ - - // relase page traversing d->arch.mm. - relinquish_mm(d); - + /* Relinquish guest resources for VT-i domain. */ if (d->vcpu[0] && VMX_DOMAIN(d->vcpu[0])) vmx_relinquish_guest_resources(d); + /* Tear down shadow mode stuff. */ + mm_teardown(d); + + /* Relinquish every page of memory. */ relinquish_memory(d, &d->xenpage_list); relinquish_memory(d, &d->page_list); diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index e3134ec7e1..e7b001bd17 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -249,17 +249,21 @@ try_to_clear_PGC_allocate(struct domain* d, struct page_info* page) } static void -relinquish_pte(struct domain* d, pte_t* pte) +mm_teardown_pte(struct domain* d, pte_t* pte, unsigned long offset) { - unsigned long mfn = pte_pfn(*pte); + pte_t old_pte; + unsigned long mfn; struct page_info* page; + old_pte = ptep_get_and_clear(&d->arch.mm, offset, pte);// acquire semantics + // vmx domain use bit[58:56] to distinguish io region from memory. // see vmx_build_physmap_table() in vmx_init.c - if (!pte_mem(*pte)) + if (!pte_mem(old_pte)) return; // domain might map IO space or acpi table pages. check it. + mfn = pte_pfn(old_pte); if (!mfn_valid(mfn)) return; page = mfn_to_page(mfn); @@ -272,17 +276,17 @@ relinquish_pte(struct domain* d, pte_t* pte) return; } - if (page_get_owner(page) == d) { + if (pte_pgc_allocated(old_pte)) { + BUG_ON(page_get_owner(page) != d); BUG_ON(get_gpfn_from_mfn(mfn) == INVALID_M2P_ENTRY); set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY); + try_to_clear_PGC_allocate(d, page); } - - try_to_clear_PGC_allocate(d, page); put_page(page); } static void -relinquish_pmd(struct domain* d, pmd_t* pmd, unsigned long offset) +mm_teardown_pmd(struct domain* d, pmd_t* pmd, unsigned long offset) { unsigned long i; pte_t* pte = pte_offset_map(pmd, offset); @@ -290,14 +294,12 @@ relinquish_pmd(struct domain* d, pmd_t* pmd, unsigned long offset) for (i = 0; i < PTRS_PER_PTE; i++, pte++) { if (!pte_present(*pte)) continue; - - relinquish_pte(d, pte); + mm_teardown_pte(d, pte, offset + (i << PAGE_SHIFT)); } - pte_free_kernel(pte_offset_map(pmd, offset)); } static void -relinquish_pud(struct domain* d, pud_t *pud, unsigned long offset) +mm_teardown_pud(struct domain* d, pud_t *pud, unsigned long offset) { unsigned long i; pmd_t *pmd = pmd_offset(pud, offset); @@ -305,14 +307,12 @@ relinquish_pud(struct domain* d, pud_t *pud, unsigned long offset) for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { if (!pmd_present(*pmd)) continue; - - relinquish_pmd(d, pmd, offset + (i << PMD_SHIFT)); + mm_teardown_pmd(d, pmd, offset + (i << PMD_SHIFT)); } - pmd_free(pmd_offset(pud, offset)); } static void -relinquish_pgd(struct domain* d, pgd_t *pgd, unsigned long offset) +mm_teardown_pgd(struct domain* d, pgd_t *pgd, unsigned long offset) { unsigned long i; pud_t *pud = pud_offset(pgd, offset); @@ -320,14 +320,12 @@ relinquish_pgd(struct domain* d, pgd_t *pgd, unsigned long offset) for (i = 0; i < PTRS_PER_PUD; i++, pud++) { if (!pud_present(*pud)) continue; - - relinquish_pud(d, pud, offset + (i << PUD_SHIFT)); + mm_teardown_pud(d, pud, offset + (i << PUD_SHIFT)); } - pud_free(pud_offset(pgd, offset)); } void -relinquish_mm(struct domain* d) +mm_teardown(struct domain* d) { struct mm_struct* mm = &d->arch.mm; unsigned long i; @@ -340,13 +338,72 @@ relinquish_mm(struct domain* d) for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { if (!pgd_present(*pgd)) continue; + mm_teardown_pgd(d, pgd, i << PGDIR_SHIFT); + } +} - relinquish_pgd(d, pgd, i << PGDIR_SHIFT); +static void +mm_p2m_teardown_pmd(struct domain* d, pmd_t* pmd, unsigned long offset) +{ + pte_free_kernel(pte_offset_map(pmd, offset)); +} + +static void +mm_p2m_teardown_pud(struct domain* d, pud_t *pud, unsigned long offset) +{ + unsigned long i; + pmd_t *pmd = pmd_offset(pud, offset); + + for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { + if (!pmd_present(*pmd)) + continue; + mm_p2m_teardown_pmd(d, pmd, offset + (i << PMD_SHIFT)); + } + pmd_free(pmd_offset(pud, offset)); +} + +static void +mm_p2m_teardown_pgd(struct domain* d, pgd_t *pgd, unsigned long offset) +{ + unsigned long i; + pud_t *pud = pud_offset(pgd, offset); + + for (i = 0; i < PTRS_PER_PUD; i++, pud++) { + if (!pud_present(*pud)) + continue; + mm_p2m_teardown_pud(d, pud, offset + (i << PUD_SHIFT)); + } + pud_free(pud_offset(pgd, offset)); +} + +static void +mm_p2m_teardown(struct domain* d) +{ + struct mm_struct* mm = &d->arch.mm; + unsigned long i; + pgd_t* pgd; + + BUG_ON(mm->pgd == NULL); + pgd = pgd_offset(mm, 0); + for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { + if (!pgd_present(*pgd)) + continue; + mm_p2m_teardown_pgd(d, pgd, i << PGDIR_SHIFT); } pgd_free(mm->pgd); mm->pgd = NULL; } +void +mm_final_teardown(struct domain* d) +{ + if (d->arch.shadow_bitmap != NULL) { + xfree(d->arch.shadow_bitmap); + d->arch.shadow_bitmap = NULL; + } + mm_p2m_teardown(d); +} + // stolen from share_xen_page_with_guest() in xen/arch/x86/mm.c void share_xen_page_with_guest(struct page_info *page, @@ -400,13 +457,6 @@ gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) { unsigned long pte; - // This function may be called from __gnttab_copy() - // during domain destruction with VNIF copy receiver. - // ** FIXME: This is not SMP-safe yet about p2m table. ** - if (unlikely(d->arch.mm.pgd == NULL)) { - BUG(); - return INVALID_MFN; - } pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT, NULL); if (!pte) { panic("gmfn_to_mfn_foreign: bad gpfn. spinning...\n"); @@ -1308,7 +1358,7 @@ expose_p2m_page(struct domain* d, unsigned long mpaddr, struct page_info* page) // pte page is allocated form xen heap.(see pte_alloc_one_kernel().) // so that the page has NULL page owner and it's reference count // is useless. - // see also relinquish_pte()'s page_get_owner() == NULL check. + // see also mm_teardown_pte()'s page_get_owner() == NULL check. BUG_ON(page_get_owner(page) != NULL); return __assign_domain_page(d, mpaddr, page_to_maddr(page), diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index 4a7fa50492..c3f4b2903d 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -422,7 +422,8 @@ extern unsigned long totalram_pages; extern int nr_swap_pages; extern void alloc_dom_xen_and_dom_io(void); -extern void relinquish_mm(struct domain* d); +extern void mm_teardown(struct domain* d); +extern void mm_final_teardown(struct domain* d); extern struct page_info * assign_new_domain_page(struct domain *d, unsigned long mpaddr); extern void assign_new_domain0_page(struct domain *d, unsigned long mpaddr); extern int __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr, unsigned long flags); From bac058316df1831d185c5be01eaab656b091ca11 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 27 Nov 2006 10:10:57 -0700 Subject: [PATCH 036/282] [IA64] Idle domain doesn't need to save and restore fph Signed-off-by: Anthony Xu --- xen/arch/ia64/xen/domain.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 3dede16491..11bd8b9fcf 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -164,8 +164,11 @@ void context_switch(struct vcpu *prev, struct vcpu *next) local_irq_save(spsr); - __ia64_save_fpu(prev->arch._thread.fph); - __ia64_load_fpu(next->arch._thread.fph); + if (!is_idle_domain(prev->domain)) + __ia64_save_fpu(prev->arch._thread.fph); + if (!is_idle_domain(next->domain)) + __ia64_load_fpu(next->arch._thread.fph); + if (VMX_DOMAIN(prev)) { vmx_save_state(prev); if (!VMX_DOMAIN(next)) { From f8cd45575d8a1cd3c03e5ba9638d573865992f27 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 28 Nov 2006 17:04:32 +0000 Subject: [PATCH 037/282] Add test_bindings back into the build -- it isn't integrated with the normal targets, because it introduces an additional dependency (libcurl), but make test/test_bindings does the right thing. Signed-off-by: Ewan Mellor --- tools/libxen/Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/libxen/Makefile b/tools/libxen/Makefile index c944b95215..6bf5d2fc25 100644 --- a/tools/libxen/Makefile +++ b/tools/libxen/Makefile @@ -48,6 +48,9 @@ libxenapi.so.$(MAJOR).$(MINOR): $(LIBXENAPI_OBJS) libxenapi.a: $(LIBXENAPI_OBJS) $(AR) rcs libxenapi.a $^ +test/test_bindings: test/test_bindings.o src/libxen.so + $(CC) $(LDFLAGS) -o $@ $< -L src -lxen + .PHONY: install install: all From b2cb3ada56c99c622d9ffb4e53b371e8112deb78 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Tue, 28 Nov 2006 17:15:22 +0000 Subject: [PATCH 038/282] Allow DMA address width to be overridden with boot parameters: In Xen: dma_bits=28 (for example) In Linux: swiotlb_bits=28 (for example) Signed-off-by: Keir Fraser --- .../arch/i386/kernel/swiotlb.c | 21 +++++++-- xen/common/memory.c | 4 +- xen/common/page_alloc.c | 47 ++++++++++++++----- xen/include/asm-ia64/config.h | 4 +- xen/include/asm-powerpc/config.h | 2 +- xen/include/asm-x86/config.h | 4 +- xen/include/xen/mm.h | 4 ++ 7 files changed, 60 insertions(+), 26 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c b/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c index be749217b1..4fa98132f4 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/swiotlb.c @@ -48,7 +48,7 @@ EXPORT_SYMBOL(swiotlb); #define IO_TLB_SHIFT 11 /* Width of DMA addresses in the IO TLB. 30 bits is a b44 limitation. */ -#define IO_TLB_DMA_BITS 30 +#define DEFAULT_IO_TLB_DMA_BITS 30 static int swiotlb_force; static char *iotlb_virt_start; @@ -98,6 +98,15 @@ static struct phys_addr { */ static DEFINE_SPINLOCK(io_tlb_lock); +static unsigned int io_tlb_dma_bits = DEFAULT_IO_TLB_DMA_BITS; +static int __init +setup_io_tlb_bits(char *str) +{ + io_tlb_dma_bits = simple_strtoul(str, NULL, 0); + return 0; +} +__setup("swiotlb_bits=", setup_io_tlb_bits); + static int __init setup_io_tlb_npages(char *str) { @@ -158,7 +167,7 @@ swiotlb_init_with_default_size (size_t default_size) int rc = xen_create_contiguous_region( (unsigned long)iotlb_virt_start + (i << IO_TLB_SHIFT), get_order(IO_TLB_SEGSIZE << IO_TLB_SHIFT), - IO_TLB_DMA_BITS); + io_tlb_dma_bits); BUG_ON(rc); } @@ -183,10 +192,12 @@ swiotlb_init_with_default_size (size_t default_size) printk(KERN_INFO "Software IO TLB enabled: \n" " Aperture: %lu megabytes\n" - " Kernel range: 0x%016lx - 0x%016lx\n", + " Kernel range: 0x%016lx - 0x%016lx\n" + " Address size: %u bits\n", bytes >> 20, (unsigned long)iotlb_virt_start, - (unsigned long)iotlb_virt_start + bytes); + (unsigned long)iotlb_virt_start + bytes, + io_tlb_dma_bits); } void @@ -654,7 +665,7 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr) int swiotlb_dma_supported (struct device *hwdev, u64 mask) { - return (mask >= ((1UL << IO_TLB_DMA_BITS) - 1)); + return (mask >= ((1UL << io_tlb_dma_bits) - 1)); } EXPORT_SYMBOL(swiotlb_init); diff --git a/xen/common/memory.c b/xen/common/memory.c index db7e9153f2..f17ae4b913 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -328,7 +328,7 @@ static long memory_exchange(XEN_GUEST_HANDLE(xen_memory_exchange_t) arg) (exch.out.address_bits < (get_order_from_pages(max_page) + PAGE_SHIFT)) ) { - if ( exch.out.address_bits < MAX_DMADOM_BITS ) + if ( exch.out.address_bits < dma_bitsize ) { rc = -ENOMEM; goto fail_early; @@ -541,7 +541,7 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE(void) arg) (reservation.address_bits < (get_order_from_pages(max_page) + PAGE_SHIFT)) ) { - if ( reservation.address_bits < MAX_DMADOM_BITS ) + if ( reservation.address_bits < dma_bitsize ) return start_extent; args.memflags = MEMF_dma; } diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 93fc193e17..2e79ce4188 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -45,19 +45,40 @@ static char opt_badpage[100] = ""; string_param("badpage", opt_badpage); +/* + * Bit width of the DMA heap. + */ +unsigned int dma_bitsize = CONFIG_DMA_BITSIZE; +unsigned long max_dma_mfn = (1UL << (CONFIG_DMA_BITSIZE - PAGE_SHIFT)) - 1; +static void parse_dma_bits(char *s) +{ + unsigned int v = simple_strtol(s, NULL, 0); + if ( v >= (sizeof(long)*8 + PAGE_SHIFT) ) + { + dma_bitsize = sizeof(long)*8 + PAGE_SHIFT; + max_dma_mfn = ~0UL; + } + else + { + dma_bitsize = v; + max_dma_mfn = (1UL << (dma_bitsize - PAGE_SHIFT)) - 1; + } +} +custom_param("dma_bits", parse_dma_bits); + /* * Amount of memory to reserve in a low-memory (<4GB) pool for specific * allocation requests. Ordinary requests will not fall back to the * lowmem emergency pool. */ -static unsigned long lowmem_emergency_pool_pages; -static void parse_lowmem_emergency_pool(char *s) +static unsigned long dma_emergency_pool_pages; +static void parse_dma_emergency_pool(char *s) { unsigned long long bytes; bytes = parse_size_and_unit(s, NULL); - lowmem_emergency_pool_pages = bytes >> PAGE_SHIFT; + dma_emergency_pool_pages = bytes >> PAGE_SHIFT; } -custom_param("lowmem_emergency_pool", parse_lowmem_emergency_pool); +custom_param("dma_emergency_pool", parse_dma_emergency_pool); #define round_pgdown(_p) ((_p)&PAGE_MASK) #define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK) @@ -248,7 +269,7 @@ unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align) #define NR_ZONES 3 #define pfn_dom_zone_type(_pfn) \ - (((_pfn) <= MAX_DMADOM_PFN) ? MEMZONE_DMADOM : MEMZONE_DOM) + (((_pfn) <= max_dma_mfn) ? MEMZONE_DMADOM : MEMZONE_DOM) static struct list_head heap[NR_ZONES][MAX_NUMNODES][MAX_ORDER+1]; @@ -278,6 +299,8 @@ void end_boot_allocator(void) if ( curr_free ) init_heap_pages(pfn_dom_zone_type(i), mfn_to_page(i), 1); } + + printk("Domain heap initialised: DMA width %u bits\n", dma_bitsize); } /* @@ -575,13 +598,13 @@ void init_domheap_pages(paddr_t ps, paddr_t pe) s_tot = round_pgup(ps) >> PAGE_SHIFT; e_tot = round_pgdown(pe) >> PAGE_SHIFT; - s_dma = min(s_tot, MAX_DMADOM_PFN + 1); - e_dma = min(e_tot, MAX_DMADOM_PFN + 1); + s_dma = min(s_tot, max_dma_mfn + 1); + e_dma = min(e_tot, max_dma_mfn + 1); if ( s_dma < e_dma ) init_heap_pages(MEMZONE_DMADOM, mfn_to_page(s_dma), e_dma - s_dma); - s_nrm = max(s_tot, MAX_DMADOM_PFN + 1); - e_nrm = max(e_tot, MAX_DMADOM_PFN + 1); + s_nrm = max(s_tot, max_dma_mfn + 1); + e_nrm = max(e_tot, max_dma_mfn + 1); if ( s_nrm < e_nrm ) init_heap_pages(MEMZONE_DOM, mfn_to_page(s_nrm), e_nrm - s_nrm); } @@ -655,7 +678,7 @@ struct page_info *__alloc_domheap_pages( if ( unlikely(pg == NULL) && ((order > MAX_ORDER) || (avail_heap_pages(MEMZONE_DMADOM,-1) < - (lowmem_emergency_pool_pages + (1UL << order)))) ) + (dma_emergency_pool_pages + (1UL << order)))) ) return NULL; } @@ -799,8 +822,8 @@ unsigned long avail_domheap_pages(void) avail_nrm = avail_heap_pages(MEMZONE_DOM,-1); avail_dma = avail_heap_pages(MEMZONE_DMADOM,-1); - if ( avail_dma > lowmem_emergency_pool_pages ) - avail_dma -= lowmem_emergency_pool_pages; + if ( avail_dma > dma_emergency_pool_pages ) + avail_dma -= dma_emergency_pool_pages; else avail_dma = 0; diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 5a07cd6d7a..5121db8623 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -41,9 +41,7 @@ #define CONFIG_IOSAPIC #define supervisor_mode_kernel (0) -#define MAX_DMADOM_BITS 30 -#define MAX_DMADOM_MASK ((1UL << MAX_DMADOM_BITS) - 1) -#define MAX_DMADOM_PFN (MAX_DMADOM_MASK >> PAGE_SHIFT) +#define CONFIG_DMA_BITSIZE 30 /* If PERFC is used, include privop maps. */ #ifdef PERF_COUNTERS diff --git a/xen/include/asm-powerpc/config.h b/xen/include/asm-powerpc/config.h index 154938fe4d..d996fdd1e0 100644 --- a/xen/include/asm-powerpc/config.h +++ b/xen/include/asm-powerpc/config.h @@ -70,7 +70,7 @@ extern char __bss_start[]; #define supervisor_mode_kernel (0) -#define MAX_DMADOM_PFN (~0UL) +#define CONFIG_DMA_BITSIZE 64 #include diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index 8dedc54a67..1ccb34edd2 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -82,9 +82,7 @@ /* Debug stack is restricted to 8kB by guard pages. */ #define DEBUG_STACK_SIZE 8192 -#define MAX_DMADOM_BITS 30 -#define MAX_DMADOM_MASK ((1UL << MAX_DMADOM_BITS) - 1) -#define MAX_DMADOM_PFN (MAX_DMADOM_MASK >> PAGE_SHIFT) +#define CONFIG_DMA_BITSIZE 30 #ifndef __ASSEMBLY__ extern unsigned long _end; /* standard ELF symbol */ diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index 4d05f6917f..7b9f76dea2 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -89,6 +89,10 @@ int assign_pages( #define MAX_ORDER 20 /* 2^20 contiguous pages */ #endif +/* DMA heap parameters. */ +extern unsigned int dma_bitsize; +extern unsigned long max_dma_mfn; + /* Automatic page scrubbing for dead domains. */ extern struct list_head page_scrub_list; #define page_scrub_schedule_work() \ From 592da6d9ee0d529d968c04e044ffb483ca3a34f2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 28 Nov 2006 17:28:43 +0000 Subject: [PATCH 039/282] Plumb the "start_paused" flag through for VM.start and VM.resume. Do not unpause the VM on start by default. This should fix problems seen recently whereby devices are not attached to the VM by the time they boot, as xm create was expecting to be able to wait for the devices before unpausing. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendAPI.py | 12 +++--- tools/python/xen/xend/XendDomain.py | 15 +++---- tools/python/xen/xend/XendDomainInfo.py | 5 ++- tools/python/xen/xm/main.py | 54 +++++++++++++++++++++---- 4 files changed, 64 insertions(+), 22 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 669ffe2bc4..4f553b9bc3 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -248,8 +248,8 @@ def valid_sr(func): # Bridge to Legacy XM API calls # ----------------------------- -def do_vm_func(fn_name, vm_ref, *args): - """Helper wrapper func to abstract away from repeative code. +def do_vm_func(fn_name, vm_ref, *args, **kwargs): + """Helper wrapper func to abstract away from repetitive code. @param fn_name: function name for XendDomain instance @type fn_name: string @@ -260,7 +260,7 @@ def do_vm_func(fn_name, vm_ref, *args): """ xendom = XendDomain.instance() fn = getattr(xendom, fn_name) - xendom.do_legacy_api_with_uuid(fn, vm_ref, *args) + xendom.do_legacy_api_with_uuid(fn, vm_ref, *args, **kwargs) return xen_api_success_void() @@ -1027,9 +1027,9 @@ class XendAPI: def vm_pause(self, session, vm_ref): return do_vm_func("domain_pause", vm_ref) def vm_resume(self, session, vm_ref, start_paused): - return do_vm_func("domain_resume", vm_ref) - def vm_start(self, session, vm_ref): - return do_vm_func("domain_start", vm_ref) + return do_vm_func("domain_resume", vm_ref, start_paused = start_paused) + def vm_start(self, session, vm_ref, start_paused): + return do_vm_func("domain_start", vm_ref, start_paused = start_paused) def vm_suspend(self, session, vm_ref): return do_vm_func("domain_suspend", vm_ref) def vm_unpause(self, session, vm_ref): diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 4d84bc14e6..27b3a1b857 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -647,18 +647,18 @@ class XendDomain: def is_valid_dev(self, klass, dev_uuid): return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None) - def do_legacy_api_with_uuid(self, fn, vm_uuid, *args): + def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs): self.domains_lock.acquire() try: for domid, dom in self.domains.items(): if dom.get_uuid == vm_uuid: - return fn(domid, *args) + return fn(domid, *args, **kwargs) if vm_uuid in self.managed_domains: domid = self.managed_domains[vm_uuid].getDomid() if domid == None: domid = self.managed_domains[vm_uuid].getName() - return fn(domid, *args) + return fn(domid, *args, **kwargs) raise XendInvalidDomain("Domain does not exist") finally: @@ -795,7 +795,7 @@ class XendDomain: raise XendError("can't write guest state file %s: %s" % (path, ex[1])) - def domain_resume(self, domname): + def domain_resume(self, domname, start_paused = False): """Resumes a domain that is persistently managed by Xend. @param domname: Domain Name @@ -827,7 +827,8 @@ class XendDomain: log.debug('Current DomainInfo state: %d' % dominfo.state) XendCheckpoint.restore(self, os.open(chkpath, os.O_RDONLY), - dominfo) + dominfo, + paused = start_paused) self._add_domain(dominfo) os.unlink(chkpath) except OSError, ex: @@ -886,7 +887,7 @@ class XendDomain: finally: self.domains_lock.release() - def domain_start(self, domid): + def domain_start(self, domid, start_paused = True): """Start a managed domain @require: Domain must not be running. @@ -907,7 +908,7 @@ class XendDomain: if dominfo.state != DOM_STATE_HALTED: raise XendError("Domain is already running") - dominfo.start(is_managed = True) + dominfo.start(is_managed = True, start_paused = start_paused) self._add_domain(dominfo) finally: self.domains_lock.release() diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 945cc3c3ca..70535174aa 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -425,7 +425,7 @@ class XendDomainInfo: # - def start(self, is_managed = False): + def start(self, is_managed = False, start_paused = True): """Attempts to start the VM by do the appropriate initialisation if it not started. """ @@ -439,7 +439,8 @@ class XendDomainInfo: self._storeDomDetails() self._registerWatches() self.refreshShutdown() - self.unpause() + if not start_paused: + self.unpause() # save running configuration if XendDomains believe domain is # persistent diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 0b7a728cd7..93d2fe1029 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -207,7 +207,13 @@ SUBCOMMAND_OPTIONS = { ('-L', '--live', 'Dump core without pausing the domain'), ('-C', '--crash', 'Crash domain after dumping core'), ), - 'restore': ( + 'start': ( + ('-p', '--paused', 'Do not unpause domain after starting it'), + ), + 'resume': ( + ('-p', '--paused', 'Do not unpause domain after resuming it'), + ), + 'restore': ( ('-p', '--paused', 'Do not unpause domain after restoring it'), ), } @@ -742,9 +748,26 @@ def xm_vcpu_list(args): print format % locals() def xm_start(args): - arg_check(args, "start", 1) - dom = args[0] - server.xend.domain.start(dom) + arg_check(args, "start", 1, 2) + + try: + (options, params) = getopt.gnu_getopt(args, 'p', ['paused']) + except getopt.GetoptError, opterr: + err(opterr) + sys.exit(1) + + paused = False + for (k, v) in options: + if k in ['-p', '--paused']: + paused = True + + if len(params) != 1: + err("Wrong number of parameters") + usage('start') + sys.exit(1) + + dom = params[0] + server.xend.domain.start(dom, paused) def xm_delete(args): arg_check(args, "delete", 1) @@ -757,9 +780,26 @@ def xm_suspend(args): server.xend.domain.suspend(dom) def xm_resume(args): - arg_check(args, "resume", 1) - dom = args[0] - server.xend.domain.resume(dom) + arg_check(args, "resume", 1, 2) + + try: + (options, params) = getopt.gnu_getopt(args, 'p', ['paused']) + except getopt.GetoptError, opterr: + err(opterr) + sys.exit(1) + + paused = False + for (k, v) in options: + if k in ['-p', '--paused']: + paused = True + + if len(params) != 1: + err("Wrong number of parameters") + usage('resume') + sys.exit(1) + + dom = params[0] + server.xend.domain.resume(dom, paused) def xm_reboot(args): arg_check(args, "reboot", 1, 3) From ea3b5838d8c4992fd254d44444bcb9216fdd227e Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 28 Nov 2006 18:00:45 +0000 Subject: [PATCH 040/282] Wait for device-bringup inside domain_start, outside the scope of the domains_lock. This makes the VM.start call blocking, but allows xm list to work while it is blocked. Move the handling of start_paused out of XendDomainInfo.start as part of this. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomain.py | 5 ++++- tools/python/xen/xend/XendDomainInfo.py | 4 +--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 27b3a1b857..839acc8da6 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -908,10 +908,13 @@ class XendDomain: if dominfo.state != DOM_STATE_HALTED: raise XendError("Domain is already running") - dominfo.start(is_managed = True, start_paused = start_paused) + dominfo.start(is_managed = True) self._add_domain(dominfo) finally: self.domains_lock.release() + dominfo.waitForDevices() + if not start_paused: + dominfo.unpause() def domain_delete(self, domid): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 70535174aa..26428a0304 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -425,7 +425,7 @@ class XendDomainInfo: # - def start(self, is_managed = False, start_paused = True): + def start(self, is_managed = False): """Attempts to start the VM by do the appropriate initialisation if it not started. """ @@ -439,8 +439,6 @@ class XendDomainInfo: self._storeDomDetails() self._registerWatches() self.refreshShutdown() - if not start_paused: - self.unpause() # save running configuration if XendDomains believe domain is # persistent From 3a22894792de7e243d1cedae233604086ce17e08 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 11:15:35 -0700 Subject: [PATCH 041/282] [IA64] import oprofile, perfmon related files from linux to xen. Signed-off-by: Isaku Yamahata Updated to 2.6.16.33 Signed-off-by: Alex Williamson --- xen/arch/ia64/linux-xen/README.origin | 8 + xen/arch/ia64/linux-xen/perfmon.c | 6852 +++++++++++++++++ .../ia64/linux-xen/perfmon_default_smpl.c | 297 + xen/arch/ia64/linux-xen/perfmon_generic.h | 45 + xen/arch/ia64/linux-xen/perfmon_itanium.h | 115 + xen/arch/ia64/linux-xen/perfmon_mckinley.h | 187 + xen/arch/ia64/linux-xen/perfmon_montecito.h | 269 + xen/arch/ia64/linux/README.origin | 3 + xen/arch/ia64/linux/carta_random.S | 54 + .../asm-ia64/linux-xen/asm/README.origin | 4 + xen/include/asm-ia64/linux-xen/asm/perfmon.h | 279 + .../linux-xen/asm/perfmon_default_smpl.h | 83 + .../asm-ia64/linux-xen/linux/README.origin | 3 + .../asm-ia64/linux-xen/linux/oprofile.h | 119 + 14 files changed, 8318 insertions(+) create mode 100644 xen/arch/ia64/linux-xen/perfmon.c create mode 100644 xen/arch/ia64/linux-xen/perfmon_default_smpl.c create mode 100644 xen/arch/ia64/linux-xen/perfmon_generic.h create mode 100644 xen/arch/ia64/linux-xen/perfmon_itanium.h create mode 100644 xen/arch/ia64/linux-xen/perfmon_mckinley.h create mode 100644 xen/arch/ia64/linux-xen/perfmon_montecito.h create mode 100644 xen/arch/ia64/linux/carta_random.S create mode 100644 xen/include/asm-ia64/linux-xen/asm/perfmon.h create mode 100644 xen/include/asm-ia64/linux-xen/asm/perfmon_default_smpl.h create mode 100644 xen/include/asm-ia64/linux-xen/linux/oprofile.h diff --git a/xen/arch/ia64/linux-xen/README.origin b/xen/arch/ia64/linux-xen/README.origin index 9a489bca74..e667b05603 100644 --- a/xen/arch/ia64/linux-xen/README.origin +++ b/xen/arch/ia64/linux-xen/README.origin @@ -33,3 +33,11 @@ unwind_i.h -> linux/arch/ia64/kernel/unwind_i.h # The files below are from Linux-2.6.16 iosapic.c -> linux/arch/ia64/kernel/iosapic.c + +# The files below are from Linux-2.6.16.33 +perfmon.c -> linux/arch/kernel/perfmon.c +perfmon_default_smpl.c -> linux/arch/kernel/perfmon_default_smpl.c +perfmon_generic.h -> linux/arch/kernel/perfmon_generic.h +perfmon_itanium.h -> linux/arch/kernel/perfmon_itanium.h +perfmon_mckinley.h -> linux/arch/kernel/perfmon_mckinley.h +perfmon_montecito.h -> linux/arch/kernel/perfmon_montecito.h diff --git a/xen/arch/ia64/linux-xen/perfmon.c b/xen/arch/ia64/linux-xen/perfmon.c new file mode 100644 index 0000000000..9b42b02b85 --- /dev/null +++ b/xen/arch/ia64/linux-xen/perfmon.c @@ -0,0 +1,6852 @@ +/* + * This file implements the perfmon-2 subsystem which is used + * to program the IA-64 Performance Monitoring Unit (PMU). + * + * The initial version of perfmon.c was written by + * Ganesh Venkitachalam, IBM Corp. + * + * Then it was modified for perfmon-1.x by Stephane Eranian and + * David Mosberger, Hewlett Packard Co. + * + * Version Perfmon-2.x is a rewrite of perfmon-1.x + * by Stephane Eranian, Hewlett Packard Co. + * + * Copyright (C) 1999-2005 Hewlett Packard Co + * Stephane Eranian + * David Mosberger-Tang + * + * More information about perfmon available at: + * http://www.hpl.hp.com/research/linux/perfmon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PERFMON +/* + * perfmon context state + */ +#define PFM_CTX_UNLOADED 1 /* context is not loaded onto any task */ +#define PFM_CTX_LOADED 2 /* context is loaded onto a task */ +#define PFM_CTX_MASKED 3 /* context is loaded but monitoring is masked due to overflow */ +#define PFM_CTX_ZOMBIE 4 /* owner of the context is closing it */ + +#define PFM_INVALID_ACTIVATION (~0UL) + +/* + * depth of message queue + */ +#define PFM_MAX_MSGS 32 +#define PFM_CTXQ_EMPTY(g) ((g)->ctx_msgq_head == (g)->ctx_msgq_tail) + +/* + * type of a PMU register (bitmask). + * bitmask structure: + * bit0 : register implemented + * bit1 : end marker + * bit2-3 : reserved + * bit4 : pmc has pmc.pm + * bit5 : pmc controls a counter (has pmc.oi), pmd is used as counter + * bit6-7 : register type + * bit8-31: reserved + */ +#define PFM_REG_NOTIMPL 0x0 /* not implemented at all */ +#define PFM_REG_IMPL 0x1 /* register implemented */ +#define PFM_REG_END 0x2 /* end marker */ +#define PFM_REG_MONITOR (0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */ +#define PFM_REG_COUNTING (0x2<<4|PFM_REG_MONITOR) /* a monitor + pmc.oi+ PMD used as a counter */ +#define PFM_REG_CONTROL (0x4<<4|PFM_REG_IMPL) /* PMU control register */ +#define PFM_REG_CONFIG (0x8<<4|PFM_REG_IMPL) /* configuration register */ +#define PFM_REG_BUFFER (0xc<<4|PFM_REG_IMPL) /* PMD used as buffer */ + +#define PMC_IS_LAST(i) (pmu_conf->pmc_desc[i].type & PFM_REG_END) +#define PMD_IS_LAST(i) (pmu_conf->pmd_desc[i].type & PFM_REG_END) + +#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) + +/* i assumed unsigned */ +#define PMC_IS_IMPL(i) (i< PMU_MAX_PMCS && (pmu_conf->pmc_desc[i].type & PFM_REG_IMPL)) +#define PMD_IS_IMPL(i) (i< PMU_MAX_PMDS && (pmu_conf->pmd_desc[i].type & PFM_REG_IMPL)) + +/* XXX: these assume that register i is implemented */ +#define PMD_IS_COUNTING(i) ((pmu_conf->pmd_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_COUNTING(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_MONITOR(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_MONITOR) == PFM_REG_MONITOR) +#define PMC_IS_CONTROL(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_CONTROL) == PFM_REG_CONTROL) + +#define PMC_DFL_VAL(i) pmu_conf->pmc_desc[i].default_value +#define PMC_RSVD_MASK(i) pmu_conf->pmc_desc[i].reserved_mask +#define PMD_PMD_DEP(i) pmu_conf->pmd_desc[i].dep_pmd[0] +#define PMC_PMD_DEP(i) pmu_conf->pmc_desc[i].dep_pmd[0] + +#define PFM_NUM_IBRS IA64_NUM_DBG_REGS +#define PFM_NUM_DBRS IA64_NUM_DBG_REGS + +#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) +#define CTX_HAS_SMPL(c) ((c)->ctx_fl_is_sampling) +#define PFM_CTX_TASK(h) (h)->ctx_task + +#define PMU_PMC_OI 5 /* position of pmc.oi bit */ + +/* XXX: does not support more than 64 PMDs */ +#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask) +#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL) + +#define CTX_USED_MONITOR(ctx, mask) (ctx)->ctx_used_monitors[0] |= (mask) + +#define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USES_DBREGS(ctx) (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1) +#define PFM_CODE_RR 0 /* requesting code range restriction */ +#define PFM_DATA_RR 1 /* requestion data range restriction */ + +#define PFM_CPUINFO_CLEAR(v) pfm_get_cpu_var(pfm_syst_info) &= ~(v) +#define PFM_CPUINFO_SET(v) pfm_get_cpu_var(pfm_syst_info) |= (v) +#define PFM_CPUINFO_GET() pfm_get_cpu_var(pfm_syst_info) + +#define RDEP(x) (1UL<<(x)) + +/* + * context protection macros + * in SMP: + * - we need to protect against CPU concurrency (spin_lock) + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * in UP: + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * + * spin_lock_irqsave()/spin_lock_irqrestore(): + * in SMP: local_irq_disable + spin_lock + * in UP : local_irq_disable + * + * spin_lock()/spin_lock(): + * in UP : removed automatically + * in SMP: protect against context accesses from other CPU. interrupts + * are not masked. This is useful for the PMU interrupt handler + * because we know we will not get PMU concurrency in that code. + */ +#define PROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_save ctx %p by [%d]\n", c, current->pid)); \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + DPRINT(("spinlocked ctx %p by [%d]\n", c, current->pid)); \ + } while(0) + +#define UNPROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_restore ctx %p by [%d]\n", c, current->pid)); \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + +#define PROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + } while(0) + + +#define UNPROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + + +#define PROTECT_CTX_NOIRQ(c) \ + do { \ + spin_lock(&(c)->ctx_lock); \ + } while(0) + +#define UNPROTECT_CTX_NOIRQ(c) \ + do { \ + spin_unlock(&(c)->ctx_lock); \ + } while(0) + + +#ifdef CONFIG_SMP + +#define GET_ACTIVATION() pfm_get_cpu_var(pmu_activation_number) +#define INC_ACTIVATION() pfm_get_cpu_var(pmu_activation_number)++ +#define SET_ACTIVATION(c) (c)->ctx_last_activation = GET_ACTIVATION() + +#else /* !CONFIG_SMP */ +#define SET_ACTIVATION(t) do {} while(0) +#define GET_ACTIVATION(t) do {} while(0) +#define INC_ACTIVATION(t) do {} while(0) +#endif /* CONFIG_SMP */ + +#define SET_PMU_OWNER(t, c) do { pfm_get_cpu_var(pmu_owner) = (t); pfm_get_cpu_var(pmu_ctx) = (c); } while(0) +#define GET_PMU_OWNER() pfm_get_cpu_var(pmu_owner) +#define GET_PMU_CTX() pfm_get_cpu_var(pmu_ctx) + +#define LOCK_PFS(g) spin_lock_irqsave(&pfm_sessions.pfs_lock, g) +#define UNLOCK_PFS(g) spin_unlock_irqrestore(&pfm_sessions.pfs_lock, g) + +#define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) + +/* + * cmp0 must be the value of pmc0 + */ +#define PMC0_HAS_OVFL(cmp0) (cmp0 & ~0x1UL) + +#define PFMFS_MAGIC 0xa0b4d889 + +/* + * debugging + */ +#define PFM_DEBUGGING 1 +#ifdef PFM_DEBUGGING +#define DPRINT(a) \ + do { \ + if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ + } while (0) + +#define DPRINT_ovfl(a) \ + do { \ + if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ + } while (0) +#endif + +/* + * 64-bit software counter structure + * + * the next_reset_type is applied to the next call to pfm_reset_regs() + */ +typedef struct { + unsigned long val; /* virtual 64bit counter value */ + unsigned long lval; /* last reset value */ + unsigned long long_reset; /* reset value on sampling overflow */ + unsigned long short_reset; /* reset value on overflow */ + unsigned long reset_pmds[4]; /* which other pmds to reset when this counter overflows */ + unsigned long smpl_pmds[4]; /* which pmds are accessed when counter overflow */ + unsigned long seed; /* seed for random-number generator */ + unsigned long mask; /* mask for random-number generator */ + unsigned int flags; /* notify/do not notify */ + unsigned long eventid; /* overflow event identifier */ +} pfm_counter_t; + +/* + * context flags + */ +typedef struct { + unsigned int block:1; /* when 1, task will blocked on user notifications */ + unsigned int system:1; /* do system wide monitoring */ + unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ + unsigned int is_sampling:1; /* true if using a custom format */ + unsigned int excl_idle:1; /* exclude idle task in system wide session */ + unsigned int going_zombie:1; /* context is zombie (MASKED+blocking) */ + unsigned int trap_reason:2; /* reason for going into pfm_handle_work() */ + unsigned int no_msg:1; /* no message sent on overflow */ + unsigned int can_restart:1; /* allowed to issue a PFM_RESTART */ + unsigned int reserved:22; +} pfm_context_flags_t; + +#define PFM_TRAP_REASON_NONE 0x0 /* default value */ +#define PFM_TRAP_REASON_BLOCK 0x1 /* we need to block on overflow */ +#define PFM_TRAP_REASON_RESET 0x2 /* we need to reset PMDs */ + + +/* + * perfmon context: encapsulates all the state of a monitoring session + */ + +typedef struct pfm_context { + spinlock_t ctx_lock; /* context protection */ + + pfm_context_flags_t ctx_flags; /* bitmask of flags (block reason incl.) */ + unsigned int ctx_state; /* state: active/inactive (no bitfield) */ + + struct task_struct *ctx_task; /* task to which context is attached */ + + unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ + + struct completion ctx_restart_done; /* use for blocking notification mode */ + + unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ + unsigned long ctx_all_pmds[4]; /* bitmask of all accessible PMDs */ + unsigned long ctx_reload_pmds[4]; /* bitmask of force reload PMD on ctxsw in */ + + unsigned long ctx_all_pmcs[4]; /* bitmask of all accessible PMCs */ + unsigned long ctx_reload_pmcs[4]; /* bitmask of force reload PMC on ctxsw in */ + unsigned long ctx_used_monitors[4]; /* bitmask of monitor PMC being used */ + + unsigned long ctx_pmcs[IA64_NUM_PMC_REGS]; /* saved copies of PMC values */ + + unsigned int ctx_used_ibrs[1]; /* bitmask of used IBR (speedup ctxsw in) */ + unsigned int ctx_used_dbrs[1]; /* bitmask of used DBR (speedup ctxsw in) */ + unsigned long ctx_dbrs[IA64_NUM_DBG_REGS]; /* DBR values (cache) when not loaded */ + unsigned long ctx_ibrs[IA64_NUM_DBG_REGS]; /* IBR values (cache) when not loaded */ + + pfm_counter_t ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */ + + u64 ctx_saved_psr_up; /* only contains psr.up value */ + + unsigned long ctx_last_activation; /* context last activation number for last_cpu */ + unsigned int ctx_last_cpu; /* CPU id of current or last CPU used (SMP only) */ + unsigned int ctx_cpu; /* cpu to which perfmon is applied (system wide) */ + + int ctx_fd; /* file descriptor used my this context */ + pfm_ovfl_arg_t ctx_ovfl_arg; /* argument to custom buffer format handler */ + + pfm_buffer_fmt_t *ctx_buf_fmt; /* buffer format callbacks */ + void *ctx_smpl_hdr; /* points to sampling buffer header kernel vaddr */ + unsigned long ctx_smpl_size; /* size of sampling buffer */ + void *ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ + + wait_queue_head_t ctx_msgq_wait; + pfm_msg_t ctx_msgq[PFM_MAX_MSGS]; + int ctx_msgq_head; + int ctx_msgq_tail; + struct fasync_struct *ctx_async_queue; + + wait_queue_head_t ctx_zombieq; /* termination cleanup wait queue */ +} pfm_context_t; + +/* + * magic number used to verify that structure is really + * a perfmon context + */ +#define PFM_IS_FILE(f) ((f)->f_op == &pfm_file_ops) + +#define PFM_GET_CTX(t) ((pfm_context_t *)(t)->thread.pfm_context) + +#ifdef CONFIG_SMP +#define SET_LAST_CPU(ctx, v) (ctx)->ctx_last_cpu = (v) +#define GET_LAST_CPU(ctx) (ctx)->ctx_last_cpu +#else +#define SET_LAST_CPU(ctx, v) do {} while(0) +#define GET_LAST_CPU(ctx) do {} while(0) +#endif + + +#define ctx_fl_block ctx_flags.block +#define ctx_fl_system ctx_flags.system +#define ctx_fl_using_dbreg ctx_flags.using_dbreg +#define ctx_fl_is_sampling ctx_flags.is_sampling +#define ctx_fl_excl_idle ctx_flags.excl_idle +#define ctx_fl_going_zombie ctx_flags.going_zombie +#define ctx_fl_trap_reason ctx_flags.trap_reason +#define ctx_fl_no_msg ctx_flags.no_msg +#define ctx_fl_can_restart ctx_flags.can_restart + +#define PFM_SET_WORK_PENDING(t, v) do { (t)->thread.pfm_needs_checking = v; } while(0); +#define PFM_GET_WORK_PENDING(t) (t)->thread.pfm_needs_checking + +/* + * global information about all sessions + * mostly used to synchronize between system wide and per-process + */ +typedef struct { + spinlock_t pfs_lock; /* lock the structure */ + + unsigned int pfs_task_sessions; /* number of per task sessions */ + unsigned int pfs_sys_sessions; /* number of per system wide sessions */ + unsigned int pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ + unsigned int pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ + struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ +} pfm_session_t; + +/* + * information about a PMC or PMD. + * dep_pmd[]: a bitmask of dependent PMD registers + * dep_pmc[]: a bitmask of dependent PMC registers + */ +typedef int (*pfm_reg_check_t)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +typedef struct { + unsigned int type; + int pm_pos; + unsigned long default_value; /* power-on default value */ + unsigned long reserved_mask; /* bitmask of reserved bits */ + pfm_reg_check_t read_check; + pfm_reg_check_t write_check; + unsigned long dep_pmd[4]; + unsigned long dep_pmc[4]; +} pfm_reg_desc_t; + +/* assume cnum is a valid monitor */ +#define PMC_PM(cnum, val) (((val) >> (pmu_conf->pmc_desc[cnum].pm_pos)) & 0x1) + +/* + * This structure is initialized at boot time and contains + * a description of the PMU main characteristics. + * + * If the probe function is defined, detection is based + * on its return value: + * - 0 means recognized PMU + * - anything else means not supported + * When the probe function is not defined, then the pmu_family field + * is used and it must match the host CPU family such that: + * - cpu->family & config->pmu_family != 0 + */ +typedef struct { + unsigned long ovfl_val; /* overflow value for counters */ + + pfm_reg_desc_t *pmc_desc; /* detailed PMC register dependencies descriptions */ + pfm_reg_desc_t *pmd_desc; /* detailed PMD register dependencies descriptions */ + + unsigned int num_pmcs; /* number of PMCS: computed at init time */ + unsigned int num_pmds; /* number of PMDS: computed at init time */ + unsigned long impl_pmcs[4]; /* bitmask of implemented PMCS */ + unsigned long impl_pmds[4]; /* bitmask of implemented PMDS */ + + char *pmu_name; /* PMU family name */ + unsigned int pmu_family; /* cpuid family pattern used to identify pmu */ + unsigned int flags; /* pmu specific flags */ + unsigned int num_ibrs; /* number of IBRS: computed at init time */ + unsigned int num_dbrs; /* number of DBRS: computed at init time */ + unsigned int num_counters; /* PMC/PMD counting pairs : computed at init time */ + int (*probe)(void); /* customized probe routine */ + unsigned int use_rr_dbregs:1; /* set if debug registers used for range restriction */ +} pmu_config_t; +/* + * PMU specific flags + */ +#define PFM_PMU_IRQ_RESEND 1 /* PMU needs explicit IRQ resend */ + +/* + * debug register related type definitions + */ +typedef struct { + unsigned long ibr_mask:56; + unsigned long ibr_plm:4; + unsigned long ibr_ig:3; + unsigned long ibr_x:1; +} ibr_mask_reg_t; + +typedef struct { + unsigned long dbr_mask:56; + unsigned long dbr_plm:4; + unsigned long dbr_ig:2; + unsigned long dbr_w:1; + unsigned long dbr_r:1; +} dbr_mask_reg_t; + +typedef union { + unsigned long val; + ibr_mask_reg_t ibr; + dbr_mask_reg_t dbr; +} dbreg_t; + + +/* + * perfmon command descriptions + */ +typedef struct { + int (*cmd_func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + char *cmd_name; + int cmd_flags; + unsigned int cmd_narg; + size_t cmd_argsize; + int (*cmd_getsize)(void *arg, size_t *sz); +} pfm_cmd_desc_t; + +#define PFM_CMD_FD 0x01 /* command requires a file descriptor */ +#define PFM_CMD_ARG_READ 0x02 /* command must read argument(s) */ +#define PFM_CMD_ARG_RW 0x04 /* command must read/write argument(s) */ +#define PFM_CMD_STOP 0x08 /* command does not work on zombie context */ + + +#define PFM_CMD_NAME(cmd) pfm_cmd_tab[(cmd)].cmd_name +#define PFM_CMD_READ_ARG(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_ARG_READ) +#define PFM_CMD_RW_ARG(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_ARG_RW) +#define PFM_CMD_USE_FD(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_FD) +#define PFM_CMD_STOPPED(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_STOP) + +#define PFM_CMD_ARG_MANY -1 /* cannot be zero */ + +typedef struct { + unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ + unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */ + unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles; /* cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_min; /* min cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_max; /* max cycles spent processing ovfl interrupts */ + unsigned long pfm_smpl_handler_calls; + unsigned long pfm_smpl_handler_cycles; + char pad[SMP_CACHE_BYTES] ____cacheline_aligned; +} pfm_stats_t; + +/* + * perfmon internal variables + */ +static pfm_stats_t pfm_stats[NR_CPUS]; +static pfm_session_t pfm_sessions; /* global sessions information */ + +static DEFINE_SPINLOCK(pfm_alt_install_check); +static pfm_intr_handler_desc_t *pfm_alt_intr_handler; + +static struct proc_dir_entry *perfmon_dir; +static pfm_uuid_t pfm_null_uuid = {0,}; + +static spinlock_t pfm_buffer_fmt_lock; +static LIST_HEAD(pfm_buffer_fmt_list); + +static pmu_config_t *pmu_conf; + +/* sysctl() controls */ +pfm_sysctl_t pfm_sysctl; +EXPORT_SYMBOL(pfm_sysctl); + +static ctl_table pfm_ctl_table[]={ + {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, + {4, "expert_mode", &pfm_sysctl.expert_mode, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, + { 0, }, +}; +static ctl_table pfm_sysctl_dir[] = { + {1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, + {0,}, +}; +static ctl_table pfm_sysctl_root[] = { + {1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, + {0,}, +}; +static struct ctl_table_header *pfm_sysctl_header; + +static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); +static int pfm_flush(struct file *filp); + +#define pfm_get_cpu_var(v) __ia64_per_cpu_var(v) +#define pfm_get_cpu_data(a,b) per_cpu(a, b) + +static inline void +pfm_put_task(struct task_struct *task) +{ + if (task != current) put_task_struct(task); +} + +static inline void +pfm_set_task_notify(struct task_struct *task) +{ + struct thread_info *info; + + info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); + set_bit(TIF_NOTIFY_RESUME, &info->flags); +} + +static inline void +pfm_clear_task_notify(void) +{ + clear_thread_flag(TIF_NOTIFY_RESUME); +} + +static inline void +pfm_reserve_page(unsigned long a) +{ + SetPageReserved(vmalloc_to_page((void *)a)); +} +static inline void +pfm_unreserve_page(unsigned long a) +{ + ClearPageReserved(vmalloc_to_page((void*)a)); +} + +static inline unsigned long +pfm_protect_ctx_ctxsw(pfm_context_t *x) +{ + spin_lock(&(x)->ctx_lock); + return 0UL; +} + +static inline void +pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) +{ + spin_unlock(&(x)->ctx_lock); +} + +static inline unsigned int +pfm_do_munmap(struct mm_struct *mm, unsigned long addr, size_t len, int acct) +{ + return do_munmap(mm, addr, len); +} + +static inline unsigned long +pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) +{ + return get_unmapped_area(file, addr, len, pgoff, flags); +} + + +static struct super_block * +pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) +{ + return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); +} + +static struct file_system_type pfm_fs_type = { + .name = "pfmfs", + .get_sb = pfmfs_get_sb, + .kill_sb = kill_anon_super, +}; + +DEFINE_PER_CPU(unsigned long, pfm_syst_info); +DEFINE_PER_CPU(struct task_struct *, pmu_owner); +DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); +DEFINE_PER_CPU(unsigned long, pmu_activation_number); +EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info); + + +/* forward declaration */ +static struct file_operations pfm_file_ops; + +/* + * forward declarations + */ +#ifndef CONFIG_SMP +static void pfm_lazy_save_regs (struct task_struct *ta); +#endif + +void dump_pmu_state(const char *); +static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + +#include "perfmon_itanium.h" +#include "perfmon_mckinley.h" +#include "perfmon_montecito.h" +#include "perfmon_generic.h" + +static pmu_config_t *pmu_confs[]={ + &pmu_conf_mont, + &pmu_conf_mck, + &pmu_conf_ita, + &pmu_conf_gen, /* must be last */ + NULL +}; + + +static int pfm_end_notify_user(pfm_context_t *ctx); + +static inline void +pfm_clear_psr_pp(void) +{ + ia64_rsm(IA64_PSR_PP); + ia64_srlz_i(); +} + +static inline void +pfm_set_psr_pp(void) +{ + ia64_ssm(IA64_PSR_PP); + ia64_srlz_i(); +} + +static inline void +pfm_clear_psr_up(void) +{ + ia64_rsm(IA64_PSR_UP); + ia64_srlz_i(); +} + +static inline void +pfm_set_psr_up(void) +{ + ia64_ssm(IA64_PSR_UP); + ia64_srlz_i(); +} + +static inline unsigned long +pfm_get_psr(void) +{ + unsigned long tmp; + tmp = ia64_getreg(_IA64_REG_PSR); + ia64_srlz_i(); + return tmp; +} + +static inline void +pfm_set_psr_l(unsigned long val) +{ + ia64_setreg(_IA64_REG_PSR_L, val); + ia64_srlz_i(); +} + +static inline void +pfm_freeze_pmu(void) +{ + ia64_set_pmc(0,1UL); + ia64_srlz_d(); +} + +static inline void +pfm_unfreeze_pmu(void) +{ + ia64_set_pmc(0,0UL); + ia64_srlz_d(); +} + +static inline void +pfm_restore_ibrs(unsigned long *ibrs, unsigned int nibrs) +{ + int i; + + for (i=0; i < nibrs; i++) { + ia64_set_ibr(i, ibrs[i]); + ia64_dv_serialize_instruction(); + } + ia64_srlz_i(); +} + +static inline void +pfm_restore_dbrs(unsigned long *dbrs, unsigned int ndbrs) +{ + int i; + + for (i=0; i < ndbrs; i++) { + ia64_set_dbr(i, dbrs[i]); + ia64_dv_serialize_data(); + } + ia64_srlz_d(); +} + +/* + * PMD[i] must be a counter. no check is made + */ +static inline unsigned long +pfm_read_soft_counter(pfm_context_t *ctx, int i) +{ + return ctx->ctx_pmds[i].val + (ia64_get_pmd(i) & pmu_conf->ovfl_val); +} + +/* + * PMD[i] must be a counter. no check is made + */ +static inline void +pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) +{ + unsigned long ovfl_val = pmu_conf->ovfl_val; + + ctx->ctx_pmds[i].val = val & ~ovfl_val; + /* + * writing to unimplemented part is ignore, so we do not need to + * mask off top part + */ + ia64_set_pmd(i, val & ovfl_val); +} + +static pfm_msg_t * +pfm_get_new_msg(pfm_context_t *ctx) +{ + int idx, next; + + next = (ctx->ctx_msgq_tail+1) % PFM_MAX_MSGS; + + DPRINT(("ctx_fd=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + if (next == ctx->ctx_msgq_head) return NULL; + + idx = ctx->ctx_msgq_tail; + ctx->ctx_msgq_tail = next; + + DPRINT(("ctx=%p head=%d tail=%d msg=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, idx)); + + return ctx->ctx_msgq+idx; +} + +static pfm_msg_t * +pfm_get_next_msg(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + DPRINT(("ctx=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + if (PFM_CTXQ_EMPTY(ctx)) return NULL; + + /* + * get oldest message + */ + msg = ctx->ctx_msgq+ctx->ctx_msgq_head; + + /* + * and move forward + */ + ctx->ctx_msgq_head = (ctx->ctx_msgq_head+1) % PFM_MAX_MSGS; + + DPRINT(("ctx=%p head=%d tail=%d type=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, msg->pfm_gen_msg.msg_type)); + + return msg; +} + +static void +pfm_reset_msgq(pfm_context_t *ctx) +{ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + DPRINT(("ctx=%p msgq reset\n", ctx)); +} + +static void * +pfm_rvmalloc(unsigned long size) +{ + void *mem; + unsigned long addr; + + size = PAGE_ALIGN(size); + mem = vmalloc(size); + if (mem) { + //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); + memset(mem, 0, size); + addr = (unsigned long)mem; + while (size > 0) { + pfm_reserve_page(addr); + addr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void +pfm_rvfree(void *mem, unsigned long size) +{ + unsigned long addr; + + if (mem) { + DPRINT(("freeing physical buffer @%p size=%lu\n", mem, size)); + addr = (unsigned long) mem; + while ((long) size > 0) { + pfm_unreserve_page(addr); + addr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } + return; +} + +static pfm_context_t * +pfm_context_alloc(void) +{ + pfm_context_t *ctx; + + /* + * allocate context descriptor + * must be able to free with interrupts disabled + */ + ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); + if (ctx) { + memset(ctx, 0, sizeof(pfm_context_t)); + DPRINT(("alloc ctx @%p\n", ctx)); + } + return ctx; +} + +static void +pfm_context_free(pfm_context_t *ctx) +{ + if (ctx) { + DPRINT(("free ctx @%p\n", ctx)); + kfree(ctx); + } +} + +static void +pfm_mask_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask, val, ovfl_mask; + int i; + + DPRINT_ovfl(("masking monitoring for [%d]\n", task->pid)); + + ovfl_mask = pmu_conf->ovfl_val; + /* + * monitoring can only be masked as a result of a valid + * counter overflow. In UP, it means that the PMU still + * has an owner. Note that the owner can be different + * from the current task. However the PMU state belongs + * to the owner. + * In SMP, a valid overflow only happens when task is + * current. Therefore if we come here, we know that + * the PMU state belongs to the current task, therefore + * we can access the live registers. + * + * So in both cases, the live register contains the owner's + * state. We can ONLY touch the PMU registers and NOT the PSR. + * + * As a consequence to this call, the thread->pmds[] array + * contains stale information which must be ignored + * when context is reloaded AND monitoring is active (see + * pfm_restart). + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + val = ia64_get_pmd(i); + + if (PMD_IS_COUNTING(i)) { + /* + * we rebuild the full 64 bit value of the counter + */ + ctx->ctx_pmds[i].val += (val & ovfl_mask); + } else { + ctx->ctx_pmds[i].val = val; + } + DPRINT_ovfl(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val & ovfl_mask)); + } + /* + * mask monitoring by setting the privilege level to 0 + * we cannot use psr.pp/psr.up for this, it is controlled by + * the user + * + * if task is current, modify actual registers, otherwise modify + * thread save state, i.e., what will be restored in pfm_load_regs() + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + ia64_set_pmc(i, th->pmcs[i] & ~0xfUL); + th->pmcs[i] &= ~0xfUL; + DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, th->pmcs[i])); + } + /* + * make all of this visible + */ + ia64_srlz_d(); +} + +/* + * must always be done with task == current + * + * context must be in MASKED state when calling + */ +static void +pfm_restore_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask, ovfl_mask; + unsigned long psr, val; + int i, is_system; + + is_system = ctx->ctx_fl_system; + ovfl_mask = pmu_conf->ovfl_val; + + if (task != current) { + printk(KERN_ERR "perfmon.%d: invalid task[%d] current[%d]\n", __LINE__, task->pid, current->pid); + return; + } + if (ctx->ctx_state != PFM_CTX_MASKED) { + printk(KERN_ERR "perfmon.%d: task[%d] current[%d] invalid state=%d\n", __LINE__, + task->pid, current->pid, ctx->ctx_state); + return; + } + psr = pfm_get_psr(); + /* + * monitoring is masked via the PMC. + * As we restore their value, we do not want each counter to + * restart right away. We stop monitoring using the PSR, + * restore the PMC (and PMD) and then re-establish the psr + * as it was. Note that there can be no pending overflow at + * this point, because monitoring was MASKED. + * + * system-wide session are pinned and self-monitoring + */ + if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* disable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + } else { + pfm_clear_psr_up(); + } + /* + * first, we restore the PMD + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + + if (PMD_IS_COUNTING(i)) { + /* + * we split the 64bit value according to + * counter width + */ + val = ctx->ctx_pmds[i].val & ovfl_mask; + ctx->ctx_pmds[i].val &= ~ovfl_mask; + } else { + val = ctx->ctx_pmds[i].val; + } + ia64_set_pmd(i, val); + + DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val)); + } + /* + * restore the PMCs + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + th->pmcs[i] = ctx->ctx_pmcs[i]; + ia64_set_pmc(i, th->pmcs[i]); + DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i])); + } + ia64_srlz_d(); + + /* + * must restore DBR/IBR because could be modified while masked + * XXX: need to optimize + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + + /* + * now restore PSR + */ + if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* enable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP); + ia64_srlz_i(); + } + pfm_set_psr_l(psr); +} + +static inline void +pfm_save_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + + ia64_srlz_d(); + + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) pmds[i] = ia64_get_pmd(i); + } +} + +/* + * reload from thread state (used for ctxw only) + */ +static inline void +pfm_restore_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + unsigned long val, ovfl_val = pmu_conf->ovfl_val; + + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + val = PMD_IS_COUNTING(i) ? pmds[i] & ovfl_val : pmds[i]; + ia64_set_pmd(i, val); + } + ia64_srlz_d(); +} + +/* + * propagate PMD from context to thread-state + */ +static inline void +pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long ovfl_val = pmu_conf->ovfl_val; + unsigned long mask = ctx->ctx_all_pmds[0]; + unsigned long val; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + + val = ctx->ctx_pmds[i].val; + + /* + * We break up the 64 bit value into 2 pieces + * the lower bits go to the machine state in the + * thread (will be reloaded on ctxsw in). + * The upper part stays in the soft-counter. + */ + if (PMD_IS_COUNTING(i)) { + ctx->ctx_pmds[i].val = val & ~ovfl_val; + val &= ovfl_val; + } + thread->pmds[i] = val; + + DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n", + i, + thread->pmds[i], + ctx->ctx_pmds[i].val)); + } +} + +/* + * propagate PMC from context to thread-state + */ +static inline void +pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long mask = ctx->ctx_all_pmcs[0]; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + /* masking 0 with ovfl_val yields 0 */ + thread->pmcs[i] = ctx->ctx_pmcs[i]; + DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i])); + } +} + + + +static inline void +pfm_restore_pmcs(unsigned long *pmcs, unsigned long mask) +{ + int i; + + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + ia64_set_pmc(i, pmcs[i]); + } + ia64_srlz_d(); +} + +static inline int +pfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b) +{ + return memcmp(a, b, sizeof(pfm_uuid_t)); +} + +static inline int +pfm_buf_fmt_exit(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_exit) ret = (*fmt->fmt_exit)(task, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_getsize(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size) +{ + int ret = 0; + if (fmt->fmt_getsize) ret = (*fmt->fmt_getsize)(task, flags, cpu, arg, size); + return ret; +} + + +static inline int +pfm_buf_fmt_validate(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_validate) ret = (*fmt->fmt_validate)(task, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_init(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_init) ret = (*fmt->fmt_init)(task, buf, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_restart(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart) ret = (*fmt->fmt_restart)(task, ctrl, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart_active) ret = (*fmt->fmt_restart_active)(task, ctrl, buf, regs); + return ret; +} + +static pfm_buffer_fmt_t * +__pfm_find_buffer_fmt(pfm_uuid_t uuid) +{ + struct list_head * pos; + pfm_buffer_fmt_t * entry; + + list_for_each(pos, &pfm_buffer_fmt_list) { + entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list); + if (pfm_uuid_cmp(uuid, entry->fmt_uuid) == 0) + return entry; + } + return NULL; +} + +/* + * find a buffer format based on its uuid + */ +static pfm_buffer_fmt_t * +pfm_find_buffer_fmt(pfm_uuid_t uuid) +{ + pfm_buffer_fmt_t * fmt; + spin_lock(&pfm_buffer_fmt_lock); + fmt = __pfm_find_buffer_fmt(uuid); + spin_unlock(&pfm_buffer_fmt_lock); + return fmt; +} + +int +pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt) +{ + int ret = 0; + + /* some sanity checks */ + if (fmt == NULL || fmt->fmt_name == NULL) return -EINVAL; + + /* we need at least a handler */ + if (fmt->fmt_handler == NULL) return -EINVAL; + + /* + * XXX: need check validity of fmt_arg_size + */ + + spin_lock(&pfm_buffer_fmt_lock); + + if (__pfm_find_buffer_fmt(fmt->fmt_uuid)) { + printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name); + ret = -EBUSY; + goto out; + } + list_add(&fmt->fmt_list, &pfm_buffer_fmt_list); + printk(KERN_INFO "perfmon: added sampling format %s\n", fmt->fmt_name); + +out: + spin_unlock(&pfm_buffer_fmt_lock); + return ret; +} +EXPORT_SYMBOL(pfm_register_buffer_fmt); + +int +pfm_unregister_buffer_fmt(pfm_uuid_t uuid) +{ + pfm_buffer_fmt_t *fmt; + int ret = 0; + + spin_lock(&pfm_buffer_fmt_lock); + + fmt = __pfm_find_buffer_fmt(uuid); + if (!fmt) { + printk(KERN_ERR "perfmon: cannot unregister format, not found\n"); + ret = -EINVAL; + goto out; + } + list_del_init(&fmt->fmt_list); + printk(KERN_INFO "perfmon: removed sampling format: %s\n", fmt->fmt_name); + +out: + spin_unlock(&pfm_buffer_fmt_lock); + return ret; + +} +EXPORT_SYMBOL(pfm_unregister_buffer_fmt); + +extern void update_pal_halt_status(int); + +static int +pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) +{ + unsigned long flags; + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(flags); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + if (is_syswide) { + /* + * cannot mix system wide and per-task sessions + */ + if (pfm_sessions.pfs_task_sessions > 0UL) { + DPRINT(("system wide not possible, %u conflicting task_sessions\n", + pfm_sessions.pfs_task_sessions)); + goto abort; + } + + if (pfm_sessions.pfs_sys_session[cpu]) goto error_conflict; + + DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id())); + + pfm_sessions.pfs_sys_session[cpu] = task; + + pfm_sessions.pfs_sys_sessions++ ; + + } else { + if (pfm_sessions.pfs_sys_sessions) goto abort; + pfm_sessions.pfs_task_sessions++; + } + + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + /* + * disable default_idle() to go to PAL_HALT + */ + update_pal_halt_status(0); + + UNLOCK_PFS(flags); + + return 0; + +error_conflict: + DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", + pfm_sessions.pfs_sys_session[cpu]->pid, + cpu)); +abort: + UNLOCK_PFS(flags); + + return -EBUSY; + +} + +static int +pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu) +{ + unsigned long flags; + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(flags); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + + if (is_syswide) { + pfm_sessions.pfs_sys_session[cpu] = NULL; + /* + * would not work with perfmon+more than one bit in cpu_mask + */ + if (ctx && ctx->ctx_fl_using_dbreg) { + if (pfm_sessions.pfs_sys_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for ctx %p sys_use_dbregs=0\n", ctx); + } else { + pfm_sessions.pfs_sys_use_dbregs--; + } + } + pfm_sessions.pfs_sys_sessions--; + } else { + pfm_sessions.pfs_task_sessions--; + } + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + /* + * if possible, enable default_idle() to go into PAL_HALT + */ + if (pfm_sessions.pfs_task_sessions == 0 && pfm_sessions.pfs_sys_sessions == 0) + update_pal_halt_status(1); + + UNLOCK_PFS(flags); + + return 0; +} + +/* + * removes virtual mapping of the sampling buffer. + * IMPORTANT: cannot be called with interrupts disable, e.g. inside + * a PROTECT_CTX() section. + */ +static int +pfm_remove_smpl_mapping(struct task_struct *task, void *vaddr, unsigned long size) +{ + int r; + + /* sanity checks */ + if (task->mm == NULL || size == 0UL || vaddr == NULL) { + printk(KERN_ERR "perfmon: pfm_remove_smpl_mapping [%d] invalid context mm=%p\n", task->pid, task->mm); + return -EINVAL; + } + + DPRINT(("smpl_vaddr=%p size=%lu\n", vaddr, size)); + + /* + * does the actual unmapping + */ + down_write(&task->mm->mmap_sem); + + DPRINT(("down_write done smpl_vaddr=%p size=%lu\n", vaddr, size)); + + r = pfm_do_munmap(task->mm, (unsigned long)vaddr, size, 0); + + up_write(&task->mm->mmap_sem); + if (r !=0) { + printk(KERN_ERR "perfmon: [%d] unable to unmap sampling buffer @%p size=%lu\n", task->pid, vaddr, size); + } + + DPRINT(("do_unmap(%p, %lu)=%d\n", vaddr, size, r)); + + return 0; +} + +/* + * free actual physical storage used by sampling buffer + */ +#if 0 +static int +pfm_free_smpl_buffer(pfm_context_t *ctx) +{ + pfm_buffer_fmt_t *fmt; + + if (ctx->ctx_smpl_hdr == NULL) goto invalid_free; + + /* + * we won't use the buffer format anymore + */ + fmt = ctx->ctx_buf_fmt; + + DPRINT(("sampling buffer @%p size %lu vaddr=%p\n", + ctx->ctx_smpl_hdr, + ctx->ctx_smpl_size, + ctx->ctx_smpl_vaddr)); + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + + /* + * free the buffer + */ + pfm_rvfree(ctx->ctx_smpl_hdr, ctx->ctx_smpl_size); + + ctx->ctx_smpl_hdr = NULL; + ctx->ctx_smpl_size = 0UL; + + return 0; + +invalid_free: + printk(KERN_ERR "perfmon: pfm_free_smpl_buffer [%d] no buffer\n", current->pid); + return -EINVAL; +} +#endif + +static inline void +pfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt) +{ + if (fmt == NULL) return; + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + +} + +/* + * pfmfs should _never_ be mounted by userland - too much of security hassle, + * no real gain from having the whole whorehouse mounted. So we don't need + * any operations on the root directory. However, we need a non-trivial + * d_name - pfm: will go nicely and kill the special-casing in procfs. + */ +static struct vfsmount *pfmfs_mnt; + +static int __init +init_pfm_fs(void) +{ + int err = register_filesystem(&pfm_fs_type); + if (!err) { + pfmfs_mnt = kern_mount(&pfm_fs_type); + err = PTR_ERR(pfmfs_mnt); + if (IS_ERR(pfmfs_mnt)) + unregister_filesystem(&pfm_fs_type); + else + err = 0; + } + return err; +} + +static void __exit +exit_pfm_fs(void) +{ + unregister_filesystem(&pfm_fs_type); + mntput(pfmfs_mnt); +} + +static ssize_t +pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) +{ + pfm_context_t *ctx; + pfm_msg_t *msg; + ssize_t ret; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return -EINVAL; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", current->pid); + return -EINVAL; + } + + /* + * check even when there is no message + */ + if (size < sizeof(pfm_msg_t)) { + DPRINT(("message is too small ctx=%p (>=%ld)\n", ctx, sizeof(pfm_msg_t))); + return -EINVAL; + } + + PROTECT_CTX(ctx, flags); + + /* + * put ourselves on the wait queue + */ + add_wait_queue(&ctx->ctx_msgq_wait, &wait); + + + for(;;) { + /* + * check wait queue + */ + + set_current_state(TASK_INTERRUPTIBLE); + + DPRINT(("head=%d tail=%d\n", ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + ret = 0; + if(PFM_CTXQ_EMPTY(ctx) == 0) break; + + UNPROTECT_CTX(ctx, flags); + + /* + * check non-blocking read + */ + ret = -EAGAIN; + if(filp->f_flags & O_NONBLOCK) break; + + /* + * check pending signals + */ + if(signal_pending(current)) { + ret = -EINTR; + break; + } + /* + * no message, so wait + */ + schedule(); + + PROTECT_CTX(ctx, flags); + } + DPRINT(("[%d] back to running ret=%ld\n", current->pid, ret)); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctx->ctx_msgq_wait, &wait); + + if (ret < 0) goto abort; + + ret = -EINVAL; + msg = pfm_get_next_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_read no msg for ctx=%p [%d]\n", ctx, current->pid); + goto abort_locked; + } + + DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); + + ret = -EFAULT; + if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); + +abort_locked: + UNPROTECT_CTX(ctx, flags); +abort: + return ret; +} + +static ssize_t +pfm_write(struct file *file, const char __user *ubuf, + size_t size, loff_t *ppos) +{ + DPRINT(("pfm_write called\n")); + return -EINVAL; +} + +static unsigned int +pfm_poll(struct file *filp, poll_table * wait) +{ + pfm_context_t *ctx; + unsigned long flags; + unsigned int mask = 0; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return 0; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", current->pid); + return 0; + } + + + DPRINT(("pfm_poll ctx_fd=%d before poll_wait\n", ctx->ctx_fd)); + + poll_wait(filp, &ctx->ctx_msgq_wait, wait); + + PROTECT_CTX(ctx, flags); + + if (PFM_CTXQ_EMPTY(ctx) == 0) + mask = POLLIN | POLLRDNORM; + + UNPROTECT_CTX(ctx, flags); + + DPRINT(("pfm_poll ctx_fd=%d mask=0x%x\n", ctx->ctx_fd, mask)); + + return mask; +} + +static int +pfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + DPRINT(("pfm_ioctl called\n")); + return -EINVAL; +} + +/* + * interrupt cannot be masked when coming here + */ +static inline int +pfm_do_fasync(int fd, struct file *filp, pfm_context_t *ctx, int on) +{ + int ret; + + ret = fasync_helper (fd, filp, on, &ctx->ctx_async_queue); + + DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + current->pid, + fd, + on, + ctx->ctx_async_queue, ret)); + + return ret; +} + +static int +pfm_fasync(int fd, struct file *filp, int on) +{ + pfm_context_t *ctx; + int ret; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_fasync bad magic [%d]\n", current->pid); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", current->pid); + return -EBADF; + } + /* + * we cannot mask interrupts during this call because this may + * may go to sleep if memory is not readily avalaible. + * + * We are protected from the conetxt disappearing by the get_fd()/put_fd() + * done in caller. Serialization of this function is ensured by caller. + */ + ret = pfm_do_fasync(fd, filp, ctx, on); + + + DPRINT(("pfm_fasync called on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + fd, + on, + ctx->ctx_async_queue, ret)); + + return ret; +} + +#ifdef CONFIG_SMP +/* + * this function is exclusively called from pfm_close(). + * The context is not protected at that time, nor are interrupts + * on the remote CPU. That's necessary to avoid deadlocks. + */ +static void +pfm_syswide_force_stop(void *info) +{ + pfm_context_t *ctx = (pfm_context_t *)info; + struct pt_regs *regs = task_pt_regs(current); + struct task_struct *owner; + unsigned long flags; + int ret; + + if (ctx->ctx_cpu != smp_processor_id()) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop for CPU%d but on CPU%d\n", + ctx->ctx_cpu, + smp_processor_id()); + return; + } + owner = GET_PMU_OWNER(); + if (owner != ctx->ctx_task) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected owner [%d] instead of [%d]\n", + smp_processor_id(), + owner->pid, ctx->ctx_task->pid); + return; + } + if (GET_PMU_CTX() != ctx) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected ctx %p instead of %p\n", + smp_processor_id(), + GET_PMU_CTX(), ctx); + return; + } + + DPRINT(("on CPU%d forcing system wide stop for [%d]\n", smp_processor_id(), ctx->ctx_task->pid)); + /* + * the context is already protected in pfm_close(), we simply + * need to mask interrupts to avoid a PMU interrupt race on + * this CPU + */ + local_irq_save(flags); + + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + DPRINT(("context_unload returned %d\n", ret)); + } + + /* + * unmask interrupts, PMU interrupts are now spurious here + */ + local_irq_restore(flags); +} + +static void +pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx) +{ + int ret; + + DPRINT(("calling CPU%d for cleanup\n", ctx->ctx_cpu)); + ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 0, 1); + DPRINT(("called CPU%d for cleanup ret=%d\n", ctx->ctx_cpu, ret)); +} +#endif /* CONFIG_SMP */ + +/* + * called for each close(). Partially free resources. + * When caller is self-monitoring, the context is unloaded. + */ +static int +pfm_flush(struct file *filp) +{ + pfm_context_t *ctx; + struct task_struct *task; + struct pt_regs *regs; + unsigned long flags; + unsigned long smpl_buf_size = 0UL; + void *smpl_buf_vaddr = NULL; + int state, is_system; + + if (PFM_IS_FILE(filp) == 0) { + DPRINT(("bad magic for\n")); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_flush: NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + /* + * remove our file from the async queue, if we use this mode. + * This can be done without the context being protected. We come + * here when the context has become unreacheable by other tasks. + * + * We may still have active monitoring at this point and we may + * end up in pfm_overflow_handler(). However, fasync_helper() + * operates with interrupts disabled and it cleans up the + * queue. If the PMU handler is called prior to entering + * fasync_helper() then it will send a signal. If it is + * invoked after, it will find an empty queue and no + * signal will be sent. In both case, we are safe + */ + if (filp->f_flags & FASYNC) { + DPRINT(("cleaning up async_queue=%p\n", ctx->ctx_async_queue)); + pfm_do_fasync (-1, filp, ctx, 0); + } + + PROTECT_CTX(ctx, flags); + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + task = PFM_CTX_TASK(ctx); + regs = task_pt_regs(task); + + DPRINT(("ctx_state=%d is_current=%d\n", + state, + task == current ? 1 : 0)); + + /* + * if state == UNLOADED, then task is NULL + */ + + /* + * we must stop and unload because we are losing access to the context. + */ + if (task == current) { +#ifdef CONFIG_SMP + /* + * the task IS the owner but it migrated to another CPU: that's bad + * but we must handle this cleanly. Unfortunately, the kernel does + * not provide a mechanism to block migration (while the context is loaded). + * + * We need to release the resource on the ORIGINAL cpu. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + /* + * keep context protected but unmask interrupt for IPI + */ + local_irq_restore(flags); + + pfm_syswide_cleanup_other_cpu(ctx); + + /* + * restore interrupt masking + */ + local_irq_save(flags); + + /* + * context is unloaded at this point + */ + } else +#endif /* CONFIG_SMP */ + { + + DPRINT(("forcing unload\n")); + /* + * stop and unload, returning with state UNLOADED + * and session unreserved. + */ + pfm_context_unload(ctx, NULL, 0, regs); + + DPRINT(("ctx_state=%d\n", ctx->ctx_state)); + } + } + + /* + * remove virtual mapping, if any, for the calling task. + * cannot reset ctx field until last user is calling close(). + * + * ctx_smpl_vaddr must never be cleared because it is needed + * by every task with access to the context + * + * When called from do_exit(), the mm context is gone already, therefore + * mm is NULL, i.e., the VMA is already gone and we do not have to + * do anything here + */ + if (ctx->ctx_smpl_vaddr && current->mm) { + smpl_buf_vaddr = ctx->ctx_smpl_vaddr; + smpl_buf_size = ctx->ctx_smpl_size; + } + + UNPROTECT_CTX(ctx, flags); + + /* + * if there was a mapping, then we systematically remove it + * at this point. Cannot be done inside critical section + * because some VM function reenables interrupts. + * + */ + if (smpl_buf_vaddr) pfm_remove_smpl_mapping(current, smpl_buf_vaddr, smpl_buf_size); + + return 0; +} +/* + * called either on explicit close() or from exit_files(). + * Only the LAST user of the file gets to this point, i.e., it is + * called only ONCE. + * + * IMPORTANT: we get called ONLY when the refcnt on the file gets to zero + * (fput()),i.e, last task to access the file. Nobody else can access the + * file at this point. + * + * When called from exit_files(), the VMA has been freed because exit_mm() + * is executed before exit_files(). + * + * When called from exit_files(), the current task is not yet ZOMBIE but we + * flush the PMU state to the context. + */ +static int +pfm_close(struct inode *inode, struct file *filp) +{ + pfm_context_t *ctx; + struct task_struct *task; + struct pt_regs *regs; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + unsigned long smpl_buf_size = 0UL; + void *smpl_buf_addr = NULL; + int free_possible = 1; + int state, is_system; + + DPRINT(("pfm_close called private=%p\n", filp->private_data)); + + if (PFM_IS_FILE(filp) == 0) { + DPRINT(("bad magic\n")); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + PROTECT_CTX(ctx, flags); + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + task = PFM_CTX_TASK(ctx); + regs = task_pt_regs(task); + + DPRINT(("ctx_state=%d is_current=%d\n", + state, + task == current ? 1 : 0)); + + /* + * if task == current, then pfm_flush() unloaded the context + */ + if (state == PFM_CTX_UNLOADED) goto doit; + + /* + * context is loaded/masked and task != current, we need to + * either force an unload or go zombie + */ + + /* + * The task is currently blocked or will block after an overflow. + * we must force it to wakeup to get out of the + * MASKED state and transition to the unloaded state by itself. + * + * This situation is only possible for per-task mode + */ + if (state == PFM_CTX_MASKED && CTX_OVFL_NOBLOCK(ctx) == 0) { + + /* + * set a "partial" zombie state to be checked + * upon return from down() in pfm_handle_work(). + * + * We cannot use the ZOMBIE state, because it is checked + * by pfm_load_regs() which is called upon wakeup from down(). + * In such case, it would free the context and then we would + * return to pfm_handle_work() which would access the + * stale context. Instead, we set a flag invisible to pfm_load_regs() + * but visible to pfm_handle_work(). + * + * For some window of time, we have a zombie context with + * ctx_state = MASKED and not ZOMBIE + */ + ctx->ctx_fl_going_zombie = 1; + + /* + * force task to wake up from MASKED state + */ + complete(&ctx->ctx_restart_done); + + DPRINT(("waking up ctx_state=%d\n", state)); + + /* + * put ourself to sleep waiting for the other + * task to report completion + * + * the context is protected by mutex, therefore there + * is no risk of being notified of completion before + * begin actually on the waitq. + */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ctx->ctx_zombieq, &wait); + + UNPROTECT_CTX(ctx, flags); + + /* + * XXX: check for signals : + * - ok for explicit close + * - not ok when coming from exit_files() + */ + schedule(); + + + PROTECT_CTX(ctx, flags); + + + remove_wait_queue(&ctx->ctx_zombieq, &wait); + set_current_state(TASK_RUNNING); + + /* + * context is unloaded at this point + */ + DPRINT(("after zombie wakeup ctx_state=%d for\n", state)); + } + else if (task != current) { +#ifdef CONFIG_SMP + /* + * switch context to zombie state + */ + ctx->ctx_state = PFM_CTX_ZOMBIE; + + DPRINT(("zombie ctx for [%d]\n", task->pid)); + /* + * cannot free the context on the spot. deferred until + * the task notices the ZOMBIE state + */ + free_possible = 0; +#else + pfm_context_unload(ctx, NULL, 0, regs); +#endif + } + +doit: + /* reload state, may have changed during opening of critical section */ + state = ctx->ctx_state; + + /* + * the context is still attached to a task (possibly current) + * we cannot destroy it right now + */ + + /* + * we must free the sampling buffer right here because + * we cannot rely on it being cleaned up later by the + * monitored task. It is not possible to free vmalloc'ed + * memory in pfm_load_regs(). Instead, we remove the buffer + * now. should there be subsequent PMU overflow originally + * meant for sampling, the will be converted to spurious + * and that's fine because the monitoring tools is gone anyway. + */ + if (ctx->ctx_smpl_hdr) { + smpl_buf_addr = ctx->ctx_smpl_hdr; + smpl_buf_size = ctx->ctx_smpl_size; + /* no more sampling */ + ctx->ctx_smpl_hdr = NULL; + ctx->ctx_fl_is_sampling = 0; + } + + DPRINT(("ctx_state=%d free_possible=%d addr=%p size=%lu\n", + state, + free_possible, + smpl_buf_addr, + smpl_buf_size)); + + if (smpl_buf_addr) pfm_exit_smpl_buffer(ctx->ctx_buf_fmt); + + /* + * UNLOADED that the session has already been unreserved. + */ + if (state == PFM_CTX_ZOMBIE) { + pfm_unreserve_session(ctx, ctx->ctx_fl_system , ctx->ctx_cpu); + } + + /* + * disconnect file descriptor from context must be done + * before we unlock. + */ + filp->private_data = NULL; + + /* + * if we free on the spot, the context is now completely unreacheable + * from the callers side. The monitored task side is also cut, so we + * can freely cut. + * + * If we have a deferred free, only the caller side is disconnected. + */ + UNPROTECT_CTX(ctx, flags); + + /* + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (smpl_buf_addr) pfm_rvfree(smpl_buf_addr, smpl_buf_size); + + /* + * return the memory used by the context + */ + if (free_possible) pfm_context_free(ctx); + + return 0; +} + +static int +pfm_no_open(struct inode *irrelevant, struct file *dontcare) +{ + DPRINT(("pfm_no_open called\n")); + return -ENXIO; +} + + + +static struct file_operations pfm_file_ops = { + .llseek = no_llseek, + .read = pfm_read, + .write = pfm_write, + .poll = pfm_poll, + .ioctl = pfm_ioctl, + .open = pfm_no_open, /* special open code to disallow open via /proc */ + .fasync = pfm_fasync, + .release = pfm_close, + .flush = pfm_flush +}; + +static int +pfmfs_delete_dentry(struct dentry *dentry) +{ + return 1; +} + +static struct dentry_operations pfmfs_dentry_operations = { + .d_delete = pfmfs_delete_dentry, +}; + + +static int +pfm_alloc_fd(struct file **cfile) +{ + int fd, ret = 0; + struct file *file = NULL; + struct inode * inode; + char name[32]; + struct qstr this; + + fd = get_unused_fd(); + if (fd < 0) return -ENFILE; + + ret = -ENFILE; + + file = get_empty_filp(); + if (!file) goto out; + + /* + * allocate a new inode + */ + inode = new_inode(pfmfs_mnt->mnt_sb); + if (!inode) goto out; + + DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); + + inode->i_mode = S_IFCHR|S_IRUGO; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + + sprintf(name, "[%lu]", inode->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = inode->i_ino; + + ret = -ENOMEM; + + /* + * allocate a new dcache entry + */ + file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); + if (!file->f_dentry) goto out; + + file->f_dentry->d_op = &pfmfs_dentry_operations; + + d_add(file->f_dentry, inode); + file->f_vfsmnt = mntget(pfmfs_mnt); + file->f_mapping = inode->i_mapping; + + file->f_op = &pfm_file_ops; + file->f_mode = FMODE_READ; + file->f_flags = O_RDONLY; + file->f_pos = 0; + + /* + * may have to delay until context is attached? + */ + fd_install(fd, file); + + /* + * the file structure we will use + */ + *cfile = file; + + return fd; +out: + if (file) put_filp(file); + put_unused_fd(fd); + return ret; +} + +static void +pfm_free_fd(int fd, struct file *file) +{ + struct files_struct *files = current->files; + struct fdtable *fdt; + + /* + * there ie no fd_uninstall(), so we do it here + */ + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + rcu_assign_pointer(fdt->fd[fd], NULL); + spin_unlock(&files->file_lock); + + if (file) + put_filp(file); + put_unused_fd(fd); +} + +static int +pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) +{ + DPRINT(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); + + while (size > 0) { + unsigned long pfn = ia64_tpa(buf) >> PAGE_SHIFT; + + + if (remap_pfn_range(vma, addr, pfn, PAGE_SIZE, PAGE_READONLY)) + return -ENOMEM; + + addr += PAGE_SIZE; + buf += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +/* + * allocate a sampling buffer and remaps it into the user address space of the task + */ +static int +pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma = NULL; + unsigned long size; + void *smpl_buf; + + + /* + * the fixed header + requested size and align to page boundary + */ + size = PAGE_ALIGN(rsize); + + DPRINT(("sampling buffer rsize=%lu size=%lu bytes\n", rsize, size)); + + /* + * check requested size to avoid Denial-of-service attacks + * XXX: may have to refine this test + * Check against address space limit. + * + * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur) + * return -ENOMEM; + */ + if (size > task->signal->rlim[RLIMIT_MEMLOCK].rlim_cur) + return -ENOMEM; + + /* + * We do the easy to undo allocations first. + * + * pfm_rvmalloc(), clears the buffer, so there is no leak + */ + smpl_buf = pfm_rvmalloc(size); + if (smpl_buf == NULL) { + DPRINT(("Can't allocate sampling buffer\n")); + return -ENOMEM; + } + + DPRINT(("smpl_buf @%p\n", smpl_buf)); + + /* allocate vma */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!vma) { + DPRINT(("Cannot allocate vma\n")); + goto error_kmem; + } + memset(vma, 0, sizeof(*vma)); + + /* + * partially initialize the vma for the sampling buffer + */ + vma->vm_mm = mm; + vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; + vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ + + /* + * Now we have everything we need and we can initialize + * and connect all the data structures + */ + + ctx->ctx_smpl_hdr = smpl_buf; + ctx->ctx_smpl_size = size; /* aligned size */ + + /* + * Let's do the difficult operations next. + * + * now we atomically find some area in the address space and + * remap the buffer in it. + */ + down_write(&task->mm->mmap_sem); + + /* find some free area in address space, must have mmap sem held */ + vma->vm_start = pfm_get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS, 0); + if (vma->vm_start == 0UL) { + DPRINT(("Cannot find unmapped area for size %ld\n", size)); + up_write(&task->mm->mmap_sem); + goto error; + } + vma->vm_end = vma->vm_start + size; + vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT; + + DPRINT(("aligned size=%ld, hdr=%p mapped @0x%lx\n", size, ctx->ctx_smpl_hdr, vma->vm_start)); + + /* can only be applied to current task, need to have the mm semaphore held when called */ + if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) { + DPRINT(("Can't remap buffer\n")); + up_write(&task->mm->mmap_sem); + goto error; + } + + /* + * now insert the vma in the vm list for the process, must be + * done with mmap lock held + */ + insert_vm_struct(mm, vma); + + mm->total_vm += size >> PAGE_SHIFT; + vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, + vma_pages(vma)); + up_write(&task->mm->mmap_sem); + + /* + * keep track of user level virtual address + */ + ctx->ctx_smpl_vaddr = (void *)vma->vm_start; + *(unsigned long *)user_vaddr = vma->vm_start; + + return 0; + +error: + kmem_cache_free(vm_area_cachep, vma); +error_kmem: + pfm_rvfree(smpl_buf, size); + + return -ENOMEM; +} + +/* + * XXX: do something better here + */ +static int +pfm_bad_permissions(struct task_struct *task) +{ + /* inspired by ptrace_attach() */ + DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n", + current->uid, + current->gid, + task->euid, + task->suid, + task->uid, + task->egid, + task->sgid)); + + return ((current->uid != task->euid) + || (current->uid != task->suid) + || (current->uid != task->uid) + || (current->gid != task->egid) + || (current->gid != task->sgid) + || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE); +} + +static int +pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) +{ + int ctx_flags; + + /* valid signal */ + + ctx_flags = pfx->ctx_flags; + + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + + /* + * cannot block in this mode + */ + if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { + DPRINT(("cannot use blocking mode when in system wide monitoring\n")); + return -EINVAL; + } + } else { + } + /* probably more to add here */ + + return 0; +} + +static int +pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ctx_flags, + unsigned int cpu, pfarg_context_t *arg) +{ + pfm_buffer_fmt_t *fmt = NULL; + unsigned long size = 0UL; + void *uaddr = NULL; + void *fmt_arg = NULL; + int ret = 0; +#define PFM_CTXARG_BUF_ARG(a) (pfm_buffer_fmt_t *)(a+1) + + /* invoke and lock buffer format, if found */ + fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id); + if (fmt == NULL) { + DPRINT(("[%d] cannot find buffer format\n", task->pid)); + return -EINVAL; + } + + /* + * buffer argument MUST be contiguous to pfarg_context_t + */ + if (fmt->fmt_arg_size) fmt_arg = PFM_CTXARG_BUF_ARG(arg); + + ret = pfm_buf_fmt_validate(fmt, task, ctx_flags, cpu, fmt_arg); + + DPRINT(("[%d] after validate(0x%x,%d,%p)=%d\n", task->pid, ctx_flags, cpu, fmt_arg, ret)); + + if (ret) goto error; + + /* link buffer format and context */ + ctx->ctx_buf_fmt = fmt; + + /* + * check if buffer format wants to use perfmon buffer allocation/mapping service + */ + ret = pfm_buf_fmt_getsize(fmt, task, ctx_flags, cpu, fmt_arg, &size); + if (ret) goto error; + + if (size) { + /* + * buffer is always remapped into the caller's address space + */ + ret = pfm_smpl_buffer_alloc(current, ctx, size, &uaddr); + if (ret) goto error; + + /* keep track of user address of buffer */ + arg->ctx_smpl_vaddr = uaddr; + } + ret = pfm_buf_fmt_init(fmt, task, ctx->ctx_smpl_hdr, ctx_flags, cpu, fmt_arg); + +error: + return ret; +} + +static void +pfm_reset_pmu_state(pfm_context_t *ctx) +{ + int i; + + /* + * install reset values for PMC. + */ + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + ctx->ctx_pmcs[i] = PMC_DFL_VAL(i); + DPRINT(("pmc[%d]=0x%lx\n", i, ctx->ctx_pmcs[i])); + } + /* + * PMD registers are set to 0UL when the context in memset() + */ + + /* + * On context switched restore, we must restore ALL pmc and ALL pmd even + * when they are not actively used by the task. In UP, the incoming process + * may otherwise pick up left over PMC, PMD state from the previous process. + * As opposed to PMD, stale PMC can cause harm to the incoming + * process because they may change what is being measured. + * Therefore, we must systematically reinstall the entire + * PMC state. In SMP, the same thing is possible on the + * same CPU but also on between 2 CPUs. + * + * The problem with PMD is information leaking especially + * to user level when psr.sp=0 + * + * There is unfortunately no easy way to avoid this problem + * on either UP or SMP. This definitively slows down the + * pfm_load_regs() function. + */ + + /* + * bitmask of all PMCs accessible to this context + * + * PMC0 is treated differently. + */ + ctx->ctx_all_pmcs[0] = pmu_conf->impl_pmcs[0] & ~0x1; + + /* + * bitmask of all PMDs that are accesible to this context + */ + ctx->ctx_all_pmds[0] = pmu_conf->impl_pmds[0]; + + DPRINT(("<%d> all_pmcs=0x%lx all_pmds=0x%lx\n", ctx->ctx_fd, ctx->ctx_all_pmcs[0],ctx->ctx_all_pmds[0])); + + /* + * useful in case of re-enable after disable + */ + ctx->ctx_used_ibrs[0] = 0UL; + ctx->ctx_used_dbrs[0] = 0UL; +} + +static int +pfm_ctx_getsize(void *arg, size_t *sz) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + pfm_buffer_fmt_t *fmt; + + *sz = 0; + + if (!pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) return 0; + + fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id); + if (fmt == NULL) { + DPRINT(("cannot find buffer format\n")); + return -EINVAL; + } + /* get just enough to copy in user parameters */ + *sz = fmt->fmt_arg_size; + DPRINT(("arg_size=%lu\n", *sz)); + + return 0; +} + + + +/* + * cannot attach if : + * - kernel task + * - task not owned by caller + * - task incompatible with context mode + */ +static int +pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task) +{ + /* + * no kernel task or task not owner by caller + */ + if (task->mm == NULL) { + DPRINT(("task [%d] has not memory context (kernel thread)\n", task->pid)); + return -EPERM; + } + if (pfm_bad_permissions(task)) { + DPRINT(("no permission to attach to [%d]\n", task->pid)); + return -EPERM; + } + /* + * cannot block in self-monitoring mode + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && task == current) { + DPRINT(("cannot load a blocking context on self for [%d]\n", task->pid)); + return -EINVAL; + } + + if (task->exit_state == EXIT_ZOMBIE) { + DPRINT(("cannot attach to zombie task [%d]\n", task->pid)); + return -EBUSY; + } + + /* + * always ok for self + */ + if (task == current) return 0; + + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { + DPRINT(("cannot attach to non-stopped task [%d] state=%ld\n", task->pid, task->state)); + return -EBUSY; + } + /* + * make sure the task is off any CPU + */ + wait_task_inactive(task); + + /* more to come... */ + + return 0; +} + +static int +pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task) +{ + struct task_struct *p = current; + int ret; + + /* XXX: need to add more checks here */ + if (pid < 2) return -EPERM; + + if (pid != current->pid) { + + read_lock(&tasklist_lock); + + p = find_task_by_pid(pid); + + /* make sure task cannot go away while we operate on it */ + if (p) get_task_struct(p); + + read_unlock(&tasklist_lock); + + if (p == NULL) return -ESRCH; + } + + ret = pfm_task_incompatible(ctx, p); + if (ret == 0) { + *task = p; + } else if (p != current) { + pfm_put_task(p); + } + return ret; +} + + + +static int +pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + struct file *filp; + int ctx_flags; + int ret; + + /* let's check the arguments first */ + ret = pfarg_is_sane(current, req); + if (ret < 0) return ret; + + ctx_flags = req->ctx_flags; + + ret = -ENOMEM; + + ctx = pfm_context_alloc(); + if (!ctx) goto error; + + ret = pfm_alloc_fd(&filp); + if (ret < 0) goto error_file; + + req->ctx_fd = ctx->ctx_fd = ret; + + /* + * attach context to file + */ + filp->private_data = ctx; + + /* + * does the user want to sample? + */ + if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { + ret = pfm_setup_buffer_fmt(current, ctx, ctx_flags, 0, req); + if (ret) goto buffer_error; + } + + /* + * init context protection lock + */ + spin_lock_init(&ctx->ctx_lock); + + /* + * context is unloaded + */ + ctx->ctx_state = PFM_CTX_UNLOADED; + + /* + * initialization of context's flags + */ + ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */ + ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; + /* + * will move to set properties + * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + */ + + /* + * init restart semaphore to locked + */ + init_completion(&ctx->ctx_restart_done); + + /* + * activation is used in SMP only + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * initialize notification message queue + */ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + init_waitqueue_head(&ctx->ctx_msgq_wait); + init_waitqueue_head(&ctx->ctx_zombieq); + + DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n", + ctx, + ctx_flags, + ctx->ctx_fl_system, + ctx->ctx_fl_block, + ctx->ctx_fl_excl_idle, + ctx->ctx_fl_no_msg, + ctx->ctx_fd)); + + /* + * initialize soft PMU state + */ + pfm_reset_pmu_state(ctx); + + return 0; + +buffer_error: + pfm_free_fd(ctx->ctx_fd, filp); + + if (ctx->ctx_buf_fmt) { + pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); + } +error_file: + pfm_context_free(ctx); + +error: + return ret; +} + +static inline unsigned long +pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset) +{ + unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset; + unsigned long new_seed, old_seed = reg->seed, mask = reg->mask; + extern unsigned long carta_random32 (unsigned long seed); + + if (reg->flags & PFM_REGFL_RANDOM) { + new_seed = carta_random32(old_seed); + val -= (old_seed & mask); /* counter values are negative numbers! */ + if ((mask >> 32) != 0) + /* construct a full 64-bit random value: */ + new_seed |= carta_random32(old_seed >> 32) << 32; + reg->seed = new_seed; + } + reg->lval = val; + return val; +} + +static void +pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i; + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + + if ((mask & 0x1UL) == 0UL) continue; + + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val)); + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } +} + +static void +pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i; + + DPRINT_ovfl(("ovfl_regs=0x%lx is_long_reset=%d\n", ovfl_regs[0], is_long_reset)); + + if (ctx->ctx_state == PFM_CTX_MASKED) { + pfm_reset_regs_masked(ctx, ovfl_regs, is_long_reset); + return; + } + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + + if ((mask & 0x1UL) == 0UL) continue; + + val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val)); + + pfm_write_soft_counter(ctx, i, val); + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + if (PMD_IS_COUNTING(i)) { + pfm_write_soft_counter(ctx, i, val); + } else { + ia64_set_pmd(i, val); + } + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } + ia64_srlz_d(); +} + +static int +pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value, pmc_pm; + unsigned long smpl_pmds, reset_pmds, impl_pmds; + unsigned int cnum, reg_flags, flags, pmc_type; + int i, can_access_pmu = 0, is_loaded, is_system, expert_mode; + int is_monitor, is_counting, state; + int ret = -EINVAL; + pfm_reg_check_t wr_func; +#define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z)) + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + task = ctx->ctx_task; + impl_pmds = pmu_conf->impl_pmds[0]; + + if (state == PFM_CTX_ZOMBIE) return -EINVAL; + + if (is_loaded) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + } + expert_mode = pfm_sysctl.expert_mode; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + reg_flags = req->reg_flags; + value = req->reg_value; + smpl_pmds = req->reg_smpl_pmds[0]; + reset_pmds = req->reg_reset_pmds[0]; + flags = 0; + + + if (cnum >= PMU_MAX_PMCS) { + DPRINT(("pmc%u is invalid\n", cnum)); + goto error; + } + + pmc_type = pmu_conf->pmc_desc[cnum].type; + pmc_pm = (value >> pmu_conf->pmc_desc[cnum].pm_pos) & 0x1; + is_counting = (pmc_type & PFM_REG_COUNTING) == PFM_REG_COUNTING ? 1 : 0; + is_monitor = (pmc_type & PFM_REG_MONITOR) == PFM_REG_MONITOR ? 1 : 0; + + /* + * we reject all non implemented PMC as well + * as attempts to modify PMC[0-3] which are used + * as status registers by the PMU + */ + if ((pmc_type & PFM_REG_IMPL) == 0 || (pmc_type & PFM_REG_CONTROL) == PFM_REG_CONTROL) { + DPRINT(("pmc%u is unimplemented or no-access pmc_type=%x\n", cnum, pmc_type)); + goto error; + } + wr_func = pmu_conf->pmc_desc[cnum].write_check; + /* + * If the PMC is a monitor, then if the value is not the default: + * - system-wide session: PMCx.pm=1 (privileged monitor) + * - per-task : PMCx.pm=0 (user monitor) + */ + if (is_monitor && value != PMC_DFL_VAL(cnum) && is_system ^ pmc_pm) { + DPRINT(("pmc%u pmc_pm=%lu is_system=%d\n", + cnum, + pmc_pm, + is_system)); + goto error; + } + + if (is_counting) { + /* + * enforce generation of overflow interrupt. Necessary on all + * CPUs. + */ + value |= 1 << PMU_PMC_OI; + + if (reg_flags & PFM_REGFL_OVFL_NOTIFY) { + flags |= PFM_REGFL_OVFL_NOTIFY; + } + + if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM; + + /* verify validity of smpl_pmds */ + if ((smpl_pmds & impl_pmds) != smpl_pmds) { + DPRINT(("invalid smpl_pmds 0x%lx for pmc%u\n", smpl_pmds, cnum)); + goto error; + } + + /* verify validity of reset_pmds */ + if ((reset_pmds & impl_pmds) != reset_pmds) { + DPRINT(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum)); + goto error; + } + } else { + if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { + DPRINT(("cannot set ovfl_notify or random on pmc%u\n", cnum)); + goto error; + } + /* eventid on non-counting monitors are ignored */ + } + + /* + * execute write checker, if any + */ + if (likely(expert_mode == 0 && wr_func)) { + ret = (*wr_func)(task, ctx, cnum, &value, regs); + if (ret) goto error; + ret = -EINVAL; + } + + /* + * no error on this register + */ + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + /* + * Now we commit the changes to the software state + */ + + /* + * update overflow information + */ + if (is_counting) { + /* + * full flag update each time a register is programmed + */ + ctx->ctx_pmds[cnum].flags = flags; + + ctx->ctx_pmds[cnum].reset_pmds[0] = reset_pmds; + ctx->ctx_pmds[cnum].smpl_pmds[0] = smpl_pmds; + ctx->ctx_pmds[cnum].eventid = req->reg_smpl_eventid; + + /* + * Mark all PMDS to be accessed as used. + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + * + * We do not update the used_monitors mask, because + * if we have not programmed them, then will be in + * a quiescent state, therefore we will not need to + * mask/restore then when context is MASKED. + */ + CTX_USED_PMD(ctx, reset_pmds); + CTX_USED_PMD(ctx, smpl_pmds); + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (state == PFM_CTX_MASKED) ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } + /* + * Needed in case the user does not initialize the equivalent + * PMD. Clearing is done indirectly via pfm_reset_pmu_state() so there is no + * possible leak here. + */ + CTX_USED_PMD(ctx, pmu_conf->pmc_desc[cnum].dep_pmd[0]); + + /* + * keep track of the monitor PMC that we are using. + * we save the value of the pmc in ctx_pmcs[] and if + * the monitoring is not stopped for the context we also + * place it in the saved state area so that it will be + * picked up later by the context switch code. + * + * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs(). + * + * The value in thread->pmcs[] may be modified on overflow, i.e., when + * monitoring needs to be stopped. + */ + if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum); + + /* + * update context state + */ + ctx->ctx_pmcs[cnum] = value; + + if (is_loaded) { + /* + * write thread state + */ + if (is_system == 0) thread->pmcs[cnum] = value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmc(cnum, value); + } +#ifdef CONFIG_SMP + else { + /* + * per-task SMP only here + * + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmcs[0] |= 1UL << cnum; + } +#endif + } + + DPRINT(("pmc[%u]=0x%lx ld=%d apmu=%d flags=0x%x all_pmcs=0x%lx used_pmds=0x%lx eventid=%ld smpl_pmds=0x%lx reset_pmds=0x%lx reloads_pmcs=0x%lx used_monitors=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + flags, + ctx->ctx_all_pmcs[0], + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].eventid, + smpl_pmds, + reset_pmds, + ctx->ctx_reload_pmcs[0], + ctx->ctx_used_monitors[0], + ctx->ctx_ovfl_regs[0])); + } + + /* + * make sure the changes are visible + */ + if (can_access_pmu) ia64_srlz_d(); + + return 0; +error: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +static int +pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value, hw_value, ovfl_mask; + unsigned int cnum; + int i, can_access_pmu = 0, state; + int is_counting, is_loaded, is_system, expert_mode; + int ret = -EINVAL; + pfm_reg_check_t wr_func; + + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + ovfl_mask = pmu_conf->ovfl_val; + task = ctx->ctx_task; + + if (unlikely(state == PFM_CTX_ZOMBIE)) return -EINVAL; + + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (likely(is_loaded)) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + } + expert_mode = pfm_sysctl.expert_mode; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + value = req->reg_value; + + if (!PMD_IS_IMPL(cnum)) { + DPRINT(("pmd[%u] is unimplemented or invalid\n", cnum)); + goto abort_mission; + } + is_counting = PMD_IS_COUNTING(cnum); + wr_func = pmu_conf->pmd_desc[cnum].write_check; + + /* + * execute write checker, if any + */ + if (unlikely(expert_mode == 0 && wr_func)) { + unsigned long v = value; + + ret = (*wr_func)(task, ctx, cnum, &v, regs); + if (ret) goto abort_mission; + + value = v; + ret = -EINVAL; + } + + /* + * no error on this register + */ + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + /* + * now commit changes to software state + */ + hw_value = value; + + /* + * update virtualized (64bits) counter + */ + if (is_counting) { + /* + * write context state + */ + ctx->ctx_pmds[cnum].lval = value; + + /* + * when context is load we use the split value + */ + if (is_loaded) { + hw_value = value & ovfl_mask; + value = value & ~ovfl_mask; + } + } + /* + * update reset values (not just for counters) + */ + ctx->ctx_pmds[cnum].long_reset = req->reg_long_reset; + ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset; + + /* + * update randomization parameters (not just for counters) + */ + ctx->ctx_pmds[cnum].seed = req->reg_random_seed; + ctx->ctx_pmds[cnum].mask = req->reg_random_mask; + + /* + * update context value + */ + ctx->ctx_pmds[cnum].val = value; + + /* + * Keep track of what we use + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + */ + CTX_USED_PMD(ctx, PMD_PMD_DEP(cnum)); + + /* + * mark this PMD register used as well + */ + CTX_USED_PMD(ctx, RDEP(cnum)); + + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (is_counting && state == PFM_CTX_MASKED) { + ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } + + if (is_loaded) { + /* + * write thread state + */ + if (is_system == 0) thread->pmds[cnum] = hw_value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmd(cnum, hw_value); + } else { +#ifdef CONFIG_SMP + /* + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmds[0] |= 1UL << cnum; +#endif + } + } + + DPRINT(("pmd[%u]=0x%lx ld=%d apmu=%d, hw_value=0x%lx ctx_pmd=0x%lx short_reset=0x%lx " + "long_reset=0x%lx notify=%c seed=0x%lx mask=0x%lx used_pmds=0x%lx reset_pmds=0x%lx reload_pmds=0x%lx all_pmds=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + hw_value, + ctx->ctx_pmds[cnum].val, + ctx->ctx_pmds[cnum].short_reset, + ctx->ctx_pmds[cnum].long_reset, + PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', + ctx->ctx_pmds[cnum].seed, + ctx->ctx_pmds[cnum].mask, + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].reset_pmds[0], + ctx->ctx_reload_pmds[0], + ctx->ctx_all_pmds[0], + ctx->ctx_ovfl_regs[0])); + } + + /* + * make changes visible + */ + if (can_access_pmu) ia64_srlz_d(); + + return 0; + +abort_mission: + /* + * for now, we have only one possibility for error + */ + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +/* + * By the way of PROTECT_CONTEXT(), interrupts are masked while we are in this function. + * Therefore we know, we do not have to worry about the PMU overflow interrupt. If an + * interrupt is delivered during the call, it will be kept pending until we leave, making + * it appears as if it had been generated at the UNPROTECT_CONTEXT(). At least we are + * guaranteed to return consistent data to the user, it may simply be old. It is not + * trivial to treat the overflow while inside the call because you may end up in + * some module sampling buffer code causing deadlocks. + */ +static int +pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + unsigned long val = 0UL, lval, ovfl_mask, sval; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned int cnum, reg_flags = 0; + int i, can_access_pmu = 0, state; + int is_loaded, is_system, is_counting, expert_mode; + int ret = -EINVAL; + pfm_reg_check_t rd_func; + + /* + * access is possible when loaded only for + * self-monitoring tasks or in UP mode + */ + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + ovfl_mask = pmu_conf->ovfl_val; + task = ctx->ctx_task; + + if (state == PFM_CTX_ZOMBIE) return -EINVAL; + + if (likely(is_loaded)) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + /* + * this can be true when not self-monitoring only in UP + */ + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + + if (can_access_pmu) ia64_srlz_d(); + } + expert_mode = pfm_sysctl.expert_mode; + + DPRINT(("ld=%d apmu=%d ctx_state=%d\n", + is_loaded, + can_access_pmu, + state)); + + /* + * on both UP and SMP, we can only read the PMD from the hardware register when + * the task is the owner of the local PMU. + */ + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + reg_flags = req->reg_flags; + + if (unlikely(!PMD_IS_IMPL(cnum))) goto error; + /* + * we can only read the register that we use. That includes + * the one we explicitely initialize AND the one we want included + * in the sampling buffer (smpl_regs). + * + * Having this restriction allows optimization in the ctxsw routine + * without compromising security (leaks) + */ + if (unlikely(!CTX_IS_USED_PMD(ctx, cnum))) goto error; + + sval = ctx->ctx_pmds[cnum].val; + lval = ctx->ctx_pmds[cnum].lval; + is_counting = PMD_IS_COUNTING(cnum); + + /* + * If the task is not the current one, then we check if the + * PMU state is still in the local live register due to lazy ctxsw. + * If true, then we read directly from the registers. + */ + if (can_access_pmu){ + val = ia64_get_pmd(cnum); + } else { + /* + * context has been saved + * if context is zombie, then task does not exist anymore. + * In this case, we use the full value saved in the context (pfm_flush_regs()). + */ + val = is_loaded ? thread->pmds[cnum] : 0UL; + } + rd_func = pmu_conf->pmd_desc[cnum].read_check; + + if (is_counting) { + /* + * XXX: need to check for overflow when loaded + */ + val &= ovfl_mask; + val += sval; + } + + /* + * execute read checker, if any + */ + if (unlikely(expert_mode == 0 && rd_func)) { + unsigned long v = val; + ret = (*rd_func)(ctx->ctx_task, ctx, cnum, &v, regs); + if (ret) goto error; + val = v; + ret = -EINVAL; + } + + PFM_REG_RETFLAG_SET(reg_flags, 0); + + DPRINT(("pmd[%u]=0x%lx\n", cnum, val)); + + /* + * update register return value, abort all if problem during copy. + * we only modify the reg_flags field. no check mode is fine because + * access has been verified upfront in sys_perfmonctl(). + */ + req->reg_value = val; + req->reg_flags = reg_flags; + req->reg_last_reset_val = lval; + } + + return 0; + +error: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +int +pfm_mod_write_pmcs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_write_pmcs(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_write_pmcs); + +int +pfm_mod_read_pmds(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_read_pmds(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_read_pmds); + +/* + * Only call this function when a process it trying to + * write the debug registers (reading is always allowed) + */ +int +pfm_use_debug_registers(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + unsigned long flags; + int ret = 0; + + if (pmu_conf->use_rr_dbregs == 0) return 0; + + DPRINT(("called for [%d]\n", task->pid)); + + /* + * do it only once + */ + if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0; + + /* + * Even on SMP, we do not need to use an atomic here because + * the only way in is via ptrace() and this is possible only when the + * process is stopped. Even in the case where the ctxsw out is not totally + * completed by the time we come here, there is no way the 'stopped' process + * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine. + * So this is always safe. + */ + if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1; + + LOCK_PFS(flags); + + /* + * We cannot allow setting breakpoints when system wide monitoring + * sessions are using the debug registers. + */ + if (pfm_sessions.pfs_sys_use_dbregs> 0) + ret = -1; + else + pfm_sessions.pfs_ptrace_use_dbregs++; + + DPRINT(("ptrace_use_dbregs=%u sys_use_dbregs=%u by [%d] ret = %d\n", + pfm_sessions.pfs_ptrace_use_dbregs, + pfm_sessions.pfs_sys_use_dbregs, + task->pid, ret)); + + UNLOCK_PFS(flags); + + return ret; +} + +/* + * This function is called for every task that exits with the + * IA64_THREAD_DBG_VALID set. This indicates a task which was + * able to use the debug registers for debugging purposes via + * ptrace(). Therefore we know it was not using them for + * perfmormance monitoring, so we only decrement the number + * of "ptraced" debug register users to keep the count up to date + */ +int +pfm_release_debug_registers(struct task_struct *task) +{ + unsigned long flags; + int ret; + + if (pmu_conf->use_rr_dbregs == 0) return 0; + + LOCK_PFS(flags); + if (pfm_sessions.pfs_ptrace_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", task->pid); + ret = -1; + } else { + pfm_sessions.pfs_ptrace_use_dbregs--; + ret = 0; + } + UNLOCK_PFS(flags); + + return ret; +} + +static int +pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task; + pfm_buffer_fmt_t *fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int state, is_system; + int ret = 0; + + state = ctx->ctx_state; + fmt = ctx->ctx_buf_fmt; + is_system = ctx->ctx_fl_system; + task = PFM_CTX_TASK(ctx); + + switch(state) { + case PFM_CTX_MASKED: + break; + case PFM_CTX_LOADED: + if (CTX_HAS_SMPL(ctx) && fmt->fmt_restart_active) break; + /* fall through */ + case PFM_CTX_UNLOADED: + case PFM_CTX_ZOMBIE: + DPRINT(("invalid state=%d\n", state)); + return -EBUSY; + default: + DPRINT(("state=%d, cannot operate (no active_restart handler)\n", state)); + return -EINVAL; + } + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + + /* sanity check */ + if (unlikely(task == NULL)) { + printk(KERN_ERR "perfmon: [%d] pfm_restart no task\n", current->pid); + return -EINVAL; + } + + if (task == current || is_system) { + + fmt = ctx->ctx_buf_fmt; + + DPRINT(("restarting self %d ovfl=0x%lx\n", + task->pid, + ctx->ctx_ovfl_regs[0])); + + if (CTX_HAS_SMPL(ctx)) { + + prefetch(ctx->ctx_smpl_hdr); + + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 0; + + if (state == PFM_CTX_LOADED) + ret = pfm_buf_fmt_restart_active(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + else + ret = pfm_buf_fmt_restart(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + } else { + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 1; + } + + if (ret == 0) { + if (rst_ctrl.bits.reset_ovfl_pmds) + pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET); + + if (rst_ctrl.bits.mask_monitoring == 0) { + DPRINT(("resuming monitoring for [%d]\n", task->pid)); + + if (state == PFM_CTX_MASKED) pfm_restore_monitoring(task); + } else { + DPRINT(("keeping monitoring stopped for [%d]\n", task->pid)); + + // cannot use pfm_stop_monitoring(task, regs); + } + } + /* + * clear overflowed PMD mask to remove any stale information + */ + ctx->ctx_ovfl_regs[0] = 0UL; + + /* + * back to LOADED state + */ + ctx->ctx_state = PFM_CTX_LOADED; + + /* + * XXX: not really useful for self monitoring + */ + ctx->ctx_fl_can_restart = 0; + + return 0; + } + + /* + * restart another task + */ + + /* + * When PFM_CTX_MASKED, we cannot issue a restart before the previous + * one is seen by the task. + */ + if (state == PFM_CTX_MASKED) { + if (ctx->ctx_fl_can_restart == 0) return -EINVAL; + /* + * will prevent subsequent restart before this one is + * seen by other task + */ + ctx->ctx_fl_can_restart = 0; + } + + /* + * if blocking, then post the semaphore is PFM_CTX_MASKED, i.e. + * the task is blocked or on its way to block. That's the normal + * restart path. If the monitoring is not masked, then the task + * can be actively monitoring and we cannot directly intervene. + * Therefore we use the trap mechanism to catch the task and + * force it to reset the buffer/reset PMDs. + * + * if non-blocking, then we ensure that the task will go into + * pfm_handle_work() before returning to user mode. + * + * We cannot explicitely reset another task, it MUST always + * be done by the task itself. This works for system wide because + * the tool that is controlling the session is logically doing + * "self-monitoring". + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && state == PFM_CTX_MASKED) { + DPRINT(("unblocking [%d] \n", task->pid)); + complete(&ctx->ctx_restart_done); + } else { + DPRINT(("[%d] armed exit trap\n", task->pid)); + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; + + PFM_SET_WORK_PENDING(task, 1); + + pfm_set_task_notify(task); + + /* + * XXX: send reschedule if task runs on another CPU + */ + } + return 0; +} + +static int +pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + unsigned int m = *(unsigned int *)arg; + + pfm_sysctl.debug = m == 0 ? 0 : 1; + + printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); + + if (m == 0) { + memset(pfm_stats, 0, sizeof(pfm_stats)); + for(m=0; m < NR_CPUS; m++) pfm_stats[m].pfm_ovfl_intr_cycles_min = ~0UL; + } + return 0; +} + +/* + * arg can be NULL and count can be zero for this function + */ +static int +pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg; + unsigned long flags; + dbreg_t dbreg; + unsigned int rnum; + int first_time; + int ret = 0, state; + int i, can_access_pmu = 0; + int is_system, is_loaded; + + if (pmu_conf->use_rr_dbregs == 0) return -EINVAL; + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + task = ctx->ctx_task; + + if (state == PFM_CTX_ZOMBIE) return -EINVAL; + + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (is_loaded) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + } + + /* + * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w + * ensuring that no real breakpoint can be installed via this call. + * + * IMPORTANT: regs can be NULL in this function + */ + + first_time = ctx->ctx_fl_using_dbreg == 0; + + /* + * don't bother if we are loaded and task is being debugged + */ + if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) { + DPRINT(("debug registers already in use for [%d]\n", task->pid)); + return -EBUSY; + } + + /* + * check for debug registers in system wide mode + * + * If though a check is done in pfm_context_load(), + * we must repeat it here, in case the registers are + * written after the context is loaded + */ + if (is_loaded) { + LOCK_PFS(flags); + + if (first_time && is_system) { + if (pfm_sessions.pfs_ptrace_use_dbregs) + ret = -EBUSY; + else + pfm_sessions.pfs_sys_use_dbregs++; + } + UNLOCK_PFS(flags); + } + + if (ret != 0) return ret; + + /* + * mark ourself as user of the debug registers for + * perfmon purposes. + */ + ctx->ctx_fl_using_dbreg = 1; + + /* + * clear hardware registers to make sure we don't + * pick up stale state. + * + * for a system wide session, we do not use + * thread.dbr, thread.ibr because this process + * never leaves the current CPU and the state + * is shared by all processes running on it + */ + if (first_time && can_access_pmu) { + DPRINT(("[%d] clearing ibrs, dbrs\n", task->pid)); + for (i=0; i < pmu_conf->num_ibrs; i++) { + ia64_set_ibr(i, 0UL); + ia64_dv_serialize_instruction(); + } + ia64_srlz_i(); + for (i=0; i < pmu_conf->num_dbrs; i++) { + ia64_set_dbr(i, 0UL); + ia64_dv_serialize_data(); + } + ia64_srlz_d(); + } + + /* + * Now install the values into the registers + */ + for (i = 0; i < count; i++, req++) { + + rnum = req->dbreg_num; + dbreg.val = req->dbreg_value; + + ret = -EINVAL; + + if ((mode == PFM_CODE_RR && rnum >= PFM_NUM_IBRS) || ((mode == PFM_DATA_RR) && rnum >= PFM_NUM_DBRS)) { + DPRINT(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", + rnum, dbreg.val, mode, i, count)); + + goto abort_mission; + } + + /* + * make sure we do not install enabled breakpoint + */ + if (rnum & 0x1) { + if (mode == PFM_CODE_RR) + dbreg.ibr.ibr_x = 0; + else + dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; + } + + PFM_REG_RETFLAG_SET(req->dbreg_flags, 0); + + /* + * Debug registers, just like PMC, can only be modified + * by a kernel call. Moreover, perfmon() access to those + * registers are centralized in this routine. The hardware + * does not modify the value of these registers, therefore, + * if we save them as they are written, we can avoid having + * to save them on context switch out. This is made possible + * by the fact that when perfmon uses debug registers, ptrace() + * won't be able to modify them concurrently. + */ + if (mode == PFM_CODE_RR) { + CTX_USED_IBR(ctx, rnum); + + if (can_access_pmu) { + ia64_set_ibr(rnum, dbreg.val); + ia64_dv_serialize_instruction(); + } + + ctx->ctx_ibrs[rnum] = dbreg.val; + + DPRINT(("write ibr%u=0x%lx used_ibrs=0x%x ld=%d apmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_ibrs[0], is_loaded, can_access_pmu)); + } else { + CTX_USED_DBR(ctx, rnum); + + if (can_access_pmu) { + ia64_set_dbr(rnum, dbreg.val); + ia64_dv_serialize_data(); + } + ctx->ctx_dbrs[rnum] = dbreg.val; + + DPRINT(("write dbr%u=0x%lx used_dbrs=0x%x ld=%d apmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_dbrs[0], is_loaded, can_access_pmu)); + } + } + + return 0; + +abort_mission: + /* + * in case it was our first attempt, we undo the global modifications + */ + if (first_time) { + LOCK_PFS(flags); + if (ctx->ctx_fl_system) { + pfm_sessions.pfs_sys_use_dbregs--; + } + UNLOCK_PFS(flags); + ctx->ctx_fl_using_dbreg = 0; + } + /* + * install error return flag + */ + PFM_REG_RETFLAG_SET(req->dbreg_flags, PFM_REG_RETFL_EINVAL); + + return ret; +} + +static int +pfm_write_ibrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_CODE_RR, ctx, arg, count, regs); +} + +static int +pfm_write_dbrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_DATA_RR, ctx, arg, count, regs); +} + +int +pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_write_ibrs(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_write_ibrs); + +int +pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_write_dbrs(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_write_dbrs); + + +static int +pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_features_t *req = (pfarg_features_t *)arg; + + req->ft_version = PFM_VERSION; + return 0; +} + +static int +pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct pt_regs *tregs; + struct task_struct *task = PFM_CTX_TASK(ctx); + int state, is_system; + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + /* + * context must be attached to issue the stop command (includes LOADED,MASKED,ZOMBIE) + */ + if (state == PFM_CTX_UNLOADED) return -EINVAL; + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + DPRINT(("task [%d] ctx_state=%d is_system=%d\n", + PFM_CTX_TASK(ctx)->pid, + state, + is_system)); + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (is_system) { + /* + * Update local PMU first + * + * disable dcr pp + */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP); + ia64_srlz_i(); + + /* + * update local cpuinfo + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + /* + * stop monitoring, does srlz.i + */ + pfm_clear_psr_pp(); + + /* + * stop monitoring in the caller + */ + ia64_psr(regs)->pp = 0; + + return 0; + } + /* + * per-task mode + */ + + if (task == current) { + /* stop monitoring at kernel level */ + pfm_clear_psr_up(); + + /* + * stop monitoring at the user level + */ + ia64_psr(regs)->up = 0; + } else { + tregs = task_pt_regs(task); + + /* + * stop monitoring at the user level + */ + ia64_psr(tregs)->up = 0; + + /* + * monitoring disabled in kernel at next reschedule + */ + ctx->ctx_saved_psr_up = 0; + DPRINT(("task=[%d]\n", task->pid)); + } + return 0; +} + + +static int +pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct pt_regs *tregs; + int state, is_system; + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + if (state != PFM_CTX_LOADED) return -EINVAL; + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (is_system) { + + /* + * set user level psr.pp for the caller + */ + ia64_psr(regs)->pp = 1; + + /* + * now update the local PMU and cpuinfo + */ + PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); + + /* + * start monitoring at kernel level + */ + pfm_set_psr_pp(); + + /* enable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP); + ia64_srlz_i(); + + return 0; + } + + /* + * per-process mode + */ + + if (ctx->ctx_task == current) { + + /* start monitoring at kernel level */ + pfm_set_psr_up(); + + /* + * activate monitoring at user level + */ + ia64_psr(regs)->up = 1; + + } else { + tregs = task_pt_regs(ctx->ctx_task); + + /* + * start monitoring at the kernel level the next + * time the task is scheduled + */ + ctx->ctx_saved_psr_up = IA64_PSR_UP; + + /* + * activate monitoring at user level + */ + ia64_psr(tregs)->up = 1; + } + return 0; +} + +static int +pfm_get_pmc_reset(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned int cnum; + int i; + int ret = -EINVAL; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + + if (!PMC_IS_IMPL(cnum)) goto abort_mission; + + req->reg_value = PMC_DFL_VAL(cnum); + + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + DPRINT(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, req->reg_value)); + } + return 0; + +abort_mission: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +static int +pfm_check_task_exist(pfm_context_t *ctx) +{ + struct task_struct *g, *t; + int ret = -ESRCH; + + read_lock(&tasklist_lock); + + do_each_thread (g, t) { + if (t->thread.pfm_context == ctx) { + ret = 0; + break; + } + } while_each_thread (g, t); + + read_unlock(&tasklist_lock); + + DPRINT(("pfm_check_task_exist: ret=%d ctx=%p\n", ret, ctx)); + + return ret; +} + +static int +pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task; + struct thread_struct *thread; + struct pfm_context_t *old; + unsigned long flags; +#ifndef CONFIG_SMP + struct task_struct *owner_task = NULL; +#endif + pfarg_load_t *req = (pfarg_load_t *)arg; + unsigned long *pmcs_source, *pmds_source; + int the_cpu; + int ret = 0; + int state, is_system, set_dbregs = 0; + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + /* + * can only load from unloaded or terminated state + */ + if (state != PFM_CTX_UNLOADED) { + DPRINT(("cannot load to [%d], invalid ctx_state=%d\n", + req->load_pid, + ctx->ctx_state)); + return -EBUSY; + } + + DPRINT(("load_pid [%d] using_dbreg=%d\n", req->load_pid, ctx->ctx_fl_using_dbreg)); + + if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) { + DPRINT(("cannot use blocking mode on self\n")); + return -EINVAL; + } + + ret = pfm_get_task(ctx, req->load_pid, &task); + if (ret) { + DPRINT(("load_pid [%d] get_task=%d\n", req->load_pid, ret)); + return ret; + } + + ret = -EINVAL; + + /* + * system wide is self monitoring only + */ + if (is_system && task != current) { + DPRINT(("system wide is self monitoring only load_pid=%d\n", + req->load_pid)); + goto error; + } + + thread = &task->thread; + + ret = 0; + /* + * cannot load a context which is using range restrictions, + * into a task that is being debugged. + */ + if (ctx->ctx_fl_using_dbreg) { + if (thread->flags & IA64_THREAD_DBG_VALID) { + ret = -EBUSY; + DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid)); + goto error; + } + LOCK_PFS(flags); + + if (is_system) { + if (pfm_sessions.pfs_ptrace_use_dbregs) { + DPRINT(("cannot load [%d] dbregs in use\n", task->pid)); + ret = -EBUSY; + } else { + pfm_sessions.pfs_sys_use_dbregs++; + DPRINT(("load [%d] increased sys_use_dbreg=%u\n", task->pid, pfm_sessions.pfs_sys_use_dbregs)); + set_dbregs = 1; + } + } + + UNLOCK_PFS(flags); + + if (ret) goto error; + } + + /* + * SMP system-wide monitoring implies self-monitoring. + * + * The programming model expects the task to + * be pinned on a CPU throughout the session. + * Here we take note of the current CPU at the + * time the context is loaded. No call from + * another CPU will be allowed. + * + * The pinning via shed_setaffinity() + * must be done by the calling task prior + * to this call. + * + * systemwide: keep track of CPU this session is supposed to run on + */ + the_cpu = ctx->ctx_cpu = smp_processor_id(); + + ret = -EBUSY; + /* + * now reserve the session + */ + ret = pfm_reserve_session(current, is_system, the_cpu); + if (ret) goto error; + + /* + * task is necessarily stopped at this point. + * + * If the previous context was zombie, then it got removed in + * pfm_save_regs(). Therefore we should not see it here. + * If we see a context, then this is an active context + * + * XXX: needs to be atomic + */ + DPRINT(("before cmpxchg() old_ctx=%p new_ctx=%p\n", + thread->pfm_context, ctx)); + + ret = -EBUSY; + old = ia64_cmpxchg(acq, &thread->pfm_context, NULL, ctx, sizeof(pfm_context_t *)); + if (old != NULL) { + DPRINT(("load_pid [%d] already has a context\n", req->load_pid)); + goto error_unres; + } + + pfm_reset_msgq(ctx); + + ctx->ctx_state = PFM_CTX_LOADED; + + /* + * link context to task + */ + ctx->ctx_task = task; + + if (is_system) { + /* + * we load as stopped + */ + PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); + } else { + thread->flags |= IA64_THREAD_PM_VALID; + } + + /* + * propagate into thread-state + */ + pfm_copy_pmds(task, ctx); + pfm_copy_pmcs(task, ctx); + + pmcs_source = thread->pmcs; + pmds_source = thread->pmds; + + /* + * always the case for system-wide + */ + if (task == current) { + + if (is_system == 0) { + + /* allow user level control */ + ia64_psr(regs)->sp = 0; + DPRINT(("clearing psr.sp for [%d]\n", task->pid)); + + SET_LAST_CPU(ctx, smp_processor_id()); + INC_ACTIVATION(); + SET_ACTIVATION(ctx); +#ifndef CONFIG_SMP + /* + * push the other task out, if any + */ + owner_task = GET_PMU_OWNER(); + if (owner_task) pfm_lazy_save_regs(owner_task); +#endif + } + /* + * load all PMD from ctx to PMU (as opposed to thread state) + * restore all PMC from ctx to PMU + */ + pfm_restore_pmds(pmds_source, ctx->ctx_all_pmds[0]); + pfm_restore_pmcs(pmcs_source, ctx->ctx_all_pmcs[0]); + + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + /* + * guaranteed safe by earlier check against DBG_VALID + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + /* + * set new ownership + */ + SET_PMU_OWNER(task, ctx); + + DPRINT(("context loaded on PMU for [%d]\n", task->pid)); + } else { + /* + * when not current, task MUST be stopped, so this is safe + */ + regs = task_pt_regs(task); + + /* force a full reload */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* initial saved psr (stopped) */ + ctx->ctx_saved_psr_up = 0UL; + ia64_psr(regs)->up = ia64_psr(regs)->pp = 0; + } + + ret = 0; + +error_unres: + if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu); +error: + /* + * we must undo the dbregs setting (for system-wide) + */ + if (ret && set_dbregs) { + LOCK_PFS(flags); + pfm_sessions.pfs_sys_use_dbregs--; + UNLOCK_PFS(flags); + } + /* + * release task, there is now a link with the context + */ + if (is_system == 0 && task != current) { + pfm_put_task(task); + + if (ret == 0) { + ret = pfm_check_task_exist(ctx); + if (ret) { + ctx->ctx_state = PFM_CTX_UNLOADED; + ctx->ctx_task = NULL; + } + } + } + return ret; +} + +/* + * in this function, we do not need to increase the use count + * for the task via get_task_struct(), because we hold the + * context lock. If the task were to disappear while having + * a context attached, it would go through pfm_exit_thread() + * which also grabs the context lock and would therefore be blocked + * until we are here. + */ +static void pfm_flush_pmds(struct task_struct *, pfm_context_t *ctx); + +static int +pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task = PFM_CTX_TASK(ctx); + struct pt_regs *tregs; + int prev_state, is_system; + int ret; + + DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); + + prev_state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + /* + * unload only when necessary + */ + if (prev_state == PFM_CTX_UNLOADED) { + DPRINT(("ctx_state=%d, nothing to do\n", prev_state)); + return 0; + } + + /* + * clear psr and dcr bits + */ + ret = pfm_stop(ctx, NULL, 0, regs); + if (ret) return ret; + + ctx->ctx_state = PFM_CTX_UNLOADED; + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (is_system) { + + /* + * Update cpuinfo + * + * local PMU is taken care of in pfm_stop() + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); + + /* + * save PMDs in context + * release ownership + */ + pfm_flush_pmds(current, ctx); + + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + */ + if (prev_state != PFM_CTX_ZOMBIE) + pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); + + /* + * disconnect context from task + */ + task->thread.pfm_context = NULL; + /* + * disconnect task from context + */ + ctx->ctx_task = NULL; + + /* + * There is nothing more to cleanup here. + */ + return 0; + } + + /* + * per-task mode + */ + tregs = task == current ? regs : task_pt_regs(task); + + if (task == current) { + /* + * cancel user level control + */ + ia64_psr(regs)->sp = 1; + + DPRINT(("setting psr.sp for [%d]\n", task->pid)); + } + /* + * save PMDs to context + * release ownership + */ + pfm_flush_pmds(task, ctx); + + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + * + * when state was ZOMBIE, we have already unreserved. + */ + if (prev_state != PFM_CTX_ZOMBIE) + pfm_unreserve_session(ctx, 0 , ctx->ctx_cpu); + + /* + * reset activation counter and psr + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * PMU state will not be restored + */ + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + /* + * break links between context and task + */ + task->thread.pfm_context = NULL; + ctx->ctx_task = NULL; + + PFM_SET_WORK_PENDING(task, 0); + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + ctx->ctx_fl_can_restart = 0; + ctx->ctx_fl_going_zombie = 0; + + DPRINT(("disconnected [%d] from context\n", task->pid)); + + return 0; +} + + +/* + * called only from exit_thread(): task == current + * we come here only if current has a context attached (loaded or masked) + */ +void +pfm_exit_thread(struct task_struct *task) +{ + pfm_context_t *ctx; + unsigned long flags; + struct pt_regs *regs = task_pt_regs(task); + int ret, state; + int free_ok = 0; + + ctx = PFM_GET_CTX(task); + + PROTECT_CTX(ctx, flags); + + DPRINT(("state=%d task [%d]\n", ctx->ctx_state, task->pid)); + + state = ctx->ctx_state; + switch(state) { + case PFM_CTX_UNLOADED: + /* + * only comes to thios function if pfm_context is not NULL, i.e., cannot + * be in unloaded state + */ + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] ctx unloaded\n", task->pid); + break; + case PFM_CTX_LOADED: + case PFM_CTX_MASKED: + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task->pid, state, ret); + } + DPRINT(("ctx unloaded for current state was %d\n", state)); + + pfm_end_notify_user(ctx); + break; + case PFM_CTX_ZOMBIE: + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task->pid, state, ret); + } + free_ok = 1; + break; + default: + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] unexpected state=%d\n", task->pid, state); + break; + } + UNPROTECT_CTX(ctx, flags); + + { u64 psr = pfm_get_psr(); + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + BUG_ON(GET_PMU_OWNER()); + BUG_ON(ia64_psr(regs)->up); + BUG_ON(ia64_psr(regs)->pp); + } + + /* + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (free_ok) pfm_context_free(ctx); +} + +/* + * functions MUST be listed in the increasing order of their index (see permfon.h) + */ +#define PFM_CMD(name, flags, arg_count, arg_type, getsz) { name, #name, flags, arg_count, sizeof(arg_type), getsz } +#define PFM_CMD_S(name, flags) { name, #name, flags, 0, 0, NULL } +#define PFM_CMD_PCLRWS (PFM_CMD_FD|PFM_CMD_ARG_RW|PFM_CMD_STOP) +#define PFM_CMD_PCLRW (PFM_CMD_FD|PFM_CMD_ARG_RW) +#define PFM_CMD_NONE { NULL, "no-cmd", 0, 0, 0, NULL} + +static pfm_cmd_desc_t pfm_cmd_tab[]={ +/* 0 */PFM_CMD_NONE, +/* 1 */PFM_CMD(pfm_write_pmcs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 2 */PFM_CMD(pfm_write_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 3 */PFM_CMD(pfm_read_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 4 */PFM_CMD_S(pfm_stop, PFM_CMD_PCLRWS), +/* 5 */PFM_CMD_S(pfm_start, PFM_CMD_PCLRWS), +/* 6 */PFM_CMD_NONE, +/* 7 */PFM_CMD_NONE, +/* 8 */PFM_CMD(pfm_context_create, PFM_CMD_ARG_RW, 1, pfarg_context_t, pfm_ctx_getsize), +/* 9 */PFM_CMD_NONE, +/* 10 */PFM_CMD_S(pfm_restart, PFM_CMD_PCLRW), +/* 11 */PFM_CMD_NONE, +/* 12 */PFM_CMD(pfm_get_features, PFM_CMD_ARG_RW, 1, pfarg_features_t, NULL), +/* 13 */PFM_CMD(pfm_debug, 0, 1, unsigned int, NULL), +/* 14 */PFM_CMD_NONE, +/* 15 */PFM_CMD(pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 16 */PFM_CMD(pfm_context_load, PFM_CMD_PCLRWS, 1, pfarg_load_t, NULL), +/* 17 */PFM_CMD_S(pfm_context_unload, PFM_CMD_PCLRWS), +/* 18 */PFM_CMD_NONE, +/* 19 */PFM_CMD_NONE, +/* 20 */PFM_CMD_NONE, +/* 21 */PFM_CMD_NONE, +/* 22 */PFM_CMD_NONE, +/* 23 */PFM_CMD_NONE, +/* 24 */PFM_CMD_NONE, +/* 25 */PFM_CMD_NONE, +/* 26 */PFM_CMD_NONE, +/* 27 */PFM_CMD_NONE, +/* 28 */PFM_CMD_NONE, +/* 29 */PFM_CMD_NONE, +/* 30 */PFM_CMD_NONE, +/* 31 */PFM_CMD_NONE, +/* 32 */PFM_CMD(pfm_write_ibrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL), +/* 33 */PFM_CMD(pfm_write_dbrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL) +}; +#define PFM_CMD_COUNT (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t)) + +static int +pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags) +{ + struct task_struct *task; + int state, old_state; + +recheck: + state = ctx->ctx_state; + task = ctx->ctx_task; + + if (task == NULL) { + DPRINT(("context %d no task, state=%d\n", ctx->ctx_fd, state)); + return 0; + } + + DPRINT(("context %d state=%d [%d] task_state=%ld must_stop=%d\n", + ctx->ctx_fd, + state, + task->pid, + task->state, PFM_CMD_STOPPED(cmd))); + + /* + * self-monitoring always ok. + * + * for system-wide the caller can either be the creator of the + * context (to one to which the context is attached to) OR + * a task running on the same CPU as the session. + */ + if (task == current || ctx->ctx_fl_system) return 0; + + /* + * we are monitoring another thread + */ + switch(state) { + case PFM_CTX_UNLOADED: + /* + * if context is UNLOADED we are safe to go + */ + return 0; + case PFM_CTX_ZOMBIE: + /* + * no command can operate on a zombie context + */ + DPRINT(("cmd %d state zombie cannot operate on context\n", cmd)); + return -EINVAL; + case PFM_CTX_MASKED: + /* + * PMU state has been saved to software even though + * the thread may still be running. + */ + if (cmd != PFM_UNLOAD_CONTEXT) return 0; + } + + /* + * context is LOADED or MASKED. Some commands may need to have + * the task stopped. + * + * We could lift this restriction for UP but it would mean that + * the user has no guarantee the task would not run between + * two successive calls to perfmonctl(). That's probably OK. + * If this user wants to ensure the task does not run, then + * the task must be stopped. + */ + if (PFM_CMD_STOPPED(cmd)) { + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { + DPRINT(("[%d] task not in stopped state\n", task->pid)); + return -EBUSY; + } + /* + * task is now stopped, wait for ctxsw out + * + * This is an interesting point in the code. + * We need to unprotect the context because + * the pfm_save_regs() routines needs to grab + * the same lock. There are danger in doing + * this because it leaves a window open for + * another task to get access to the context + * and possibly change its state. The one thing + * that is not possible is for the context to disappear + * because we are protected by the VFS layer, i.e., + * get_fd()/put_fd(). + */ + old_state = state; + + UNPROTECT_CTX(ctx, flags); + + wait_task_inactive(task); + + PROTECT_CTX(ctx, flags); + + /* + * we must recheck to verify if state has changed + */ + if (ctx->ctx_state != old_state) { + DPRINT(("old_state=%d new_state=%d\n", old_state, ctx->ctx_state)); + goto recheck; + } + } + return 0; +} + +/* + * system-call entry point (must return long) + */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void __user *arg, int count) +{ + struct file *file = NULL; + pfm_context_t *ctx = NULL; + unsigned long flags = 0UL; + void *args_k = NULL; + long ret; /* will expand int return types */ + size_t base_sz, sz, xtra_sz = 0; + int narg, completed_args = 0, call_made = 0, cmd_flags; + int (*func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + int (*getsize)(void *arg, size_t *sz); +#define PFM_MAX_ARGSIZE 4096 + + /* + * reject any call if perfmon was disabled at initialization + */ + if (unlikely(pmu_conf == NULL)) return -ENOSYS; + + if (unlikely(cmd < 0 || cmd >= PFM_CMD_COUNT)) { + DPRINT(("invalid cmd=%d\n", cmd)); + return -EINVAL; + } + + func = pfm_cmd_tab[cmd].cmd_func; + narg = pfm_cmd_tab[cmd].cmd_narg; + base_sz = pfm_cmd_tab[cmd].cmd_argsize; + getsize = pfm_cmd_tab[cmd].cmd_getsize; + cmd_flags = pfm_cmd_tab[cmd].cmd_flags; + + if (unlikely(func == NULL)) { + DPRINT(("invalid cmd=%d\n", cmd)); + return -EINVAL; + } + + DPRINT(("cmd=%s idx=%d narg=0x%x argsz=%lu count=%d\n", + PFM_CMD_NAME(cmd), + cmd, + narg, + base_sz, + count)); + + /* + * check if number of arguments matches what the command expects + */ + if (unlikely((narg == PFM_CMD_ARG_MANY && count <= 0) || (narg > 0 && narg != count))) + return -EINVAL; + +restart_args: + sz = xtra_sz + base_sz*count; + /* + * limit abuse to min page size + */ + if (unlikely(sz > PFM_MAX_ARGSIZE)) { + printk(KERN_ERR "perfmon: [%d] argument too big %lu\n", current->pid, sz); + return -E2BIG; + } + + /* + * allocate default-sized argument buffer + */ + if (likely(count && args_k == NULL)) { + args_k = kmalloc(PFM_MAX_ARGSIZE, GFP_KERNEL); + if (args_k == NULL) return -ENOMEM; + } + + ret = -EFAULT; + + /* + * copy arguments + * + * assume sz = 0 for command without parameters + */ + if (sz && copy_from_user(args_k, arg, sz)) { + DPRINT(("cannot copy_from_user %lu bytes @%p\n", sz, arg)); + goto error_args; + } + + /* + * check if command supports extra parameters + */ + if (completed_args == 0 && getsize) { + /* + * get extra parameters size (based on main argument) + */ + ret = (*getsize)(args_k, &xtra_sz); + if (ret) goto error_args; + + completed_args = 1; + + DPRINT(("restart_args sz=%lu xtra_sz=%lu\n", sz, xtra_sz)); + + /* retry if necessary */ + if (likely(xtra_sz)) goto restart_args; + } + + if (unlikely((cmd_flags & PFM_CMD_FD) == 0)) goto skip_fd; + + ret = -EBADF; + + file = fget(fd); + if (unlikely(file == NULL)) { + DPRINT(("invalid fd %d\n", fd)); + goto error_args; + } + if (unlikely(PFM_IS_FILE(file) == 0)) { + DPRINT(("fd %d not related to perfmon\n", fd)); + goto error_args; + } + + ctx = (pfm_context_t *)file->private_data; + if (unlikely(ctx == NULL)) { + DPRINT(("no context for fd %d\n", fd)); + goto error_args; + } + prefetch(&ctx->ctx_state); + + PROTECT_CTX(ctx, flags); + + /* + * check task is stopped + */ + ret = pfm_check_task_state(ctx, cmd, flags); + if (unlikely(ret)) goto abort_locked; + +skip_fd: + ret = (*func)(ctx, args_k, count, task_pt_regs(current)); + + call_made = 1; + +abort_locked: + if (likely(ctx)) { + DPRINT(("context unlocked\n")); + UNPROTECT_CTX(ctx, flags); + } + + /* copy argument back to user, if needed */ + if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT; + +error_args: + if (file) + fput(file); + + kfree(args_k); + + DPRINT(("cmd=%s ret=%ld\n", PFM_CMD_NAME(cmd), ret)); + + return ret; +} + +static void +pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_regs *regs) +{ + pfm_buffer_fmt_t *fmt = ctx->ctx_buf_fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int state; + int ret = 0; + + state = ctx->ctx_state; + /* + * Unlock sampling buffer and reset index atomically + * XXX: not really needed when blocking + */ + if (CTX_HAS_SMPL(ctx)) { + + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 0; + + if (state == PFM_CTX_LOADED) + ret = pfm_buf_fmt_restart_active(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + else + ret = pfm_buf_fmt_restart(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + } else { + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 1; + } + + if (ret == 0) { + if (rst_ctrl.bits.reset_ovfl_pmds) { + pfm_reset_regs(ctx, &ovfl_regs, PFM_PMD_LONG_RESET); + } + if (rst_ctrl.bits.mask_monitoring == 0) { + DPRINT(("resuming monitoring\n")); + if (ctx->ctx_state == PFM_CTX_MASKED) pfm_restore_monitoring(current); + } else { + DPRINT(("stopping monitoring\n")); + //pfm_stop_monitoring(current, regs); + } + ctx->ctx_state = PFM_CTX_LOADED; + } +} + +/* + * context MUST BE LOCKED when calling + * can only be called for current + */ +static void +pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs) +{ + int ret; + + DPRINT(("entering for [%d]\n", current->pid)); + + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "pfm_context_force_terminate: [%d] unloaded failed with %d\n", current->pid, ret); + } + + /* + * and wakeup controlling task, indicating we are now disconnected + */ + wake_up_interruptible(&ctx->ctx_zombieq); + + /* + * given that context is still locked, the controlling + * task will only get access when we return from + * pfm_handle_work(). + */ +} + +static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); + /* + * pfm_handle_work() can be called with interrupts enabled + * (TIF_NEED_RESCHED) or disabled. The down_interruptible + * call may sleep, therefore we must re-enable interrupts + * to avoid deadlocks. It is safe to do so because this function + * is called ONLY when returning to user level (PUStk=1), in which case + * there is no risk of kernel stack overflow due to deep + * interrupt nesting. + */ +void +pfm_handle_work(void) +{ + pfm_context_t *ctx; + struct pt_regs *regs; + unsigned long flags, dummy_flags; + unsigned long ovfl_regs; + unsigned int reason; + int ret; + + ctx = PFM_GET_CTX(current); + if (ctx == NULL) { + printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); + return; + } + + PROTECT_CTX(ctx, flags); + + PFM_SET_WORK_PENDING(current, 0); + + pfm_clear_task_notify(); + + regs = task_pt_regs(current); + + /* + * extract reason for being here and clear + */ + reason = ctx->ctx_fl_trap_reason; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + ovfl_regs = ctx->ctx_ovfl_regs[0]; + + DPRINT(("reason=%d state=%d\n", reason, ctx->ctx_state)); + + /* + * must be done before we check for simple-reset mode + */ + if (ctx->ctx_fl_going_zombie || ctx->ctx_state == PFM_CTX_ZOMBIE) goto do_zombie; + + + //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; + if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; + + /* + * restore interrupt mask to what it was on entry. + * Could be enabled/diasbled. + */ + UNPROTECT_CTX(ctx, flags); + + /* + * force interrupt enable because of down_interruptible() + */ + local_irq_enable(); + + DPRINT(("before block sleeping\n")); + + /* + * may go through without blocking on SMP systems + * if restart has been received already by the time we call down() + */ + ret = wait_for_completion_interruptible(&ctx->ctx_restart_done); + + DPRINT(("after block sleeping ret=%d\n", ret)); + + /* + * lock context and mask interrupts again + * We save flags into a dummy because we may have + * altered interrupts mask compared to entry in this + * function. + */ + PROTECT_CTX(ctx, dummy_flags); + + /* + * we need to read the ovfl_regs only after wake-up + * because we may have had pfm_write_pmds() in between + * and that can changed PMD values and therefore + * ovfl_regs is reset for these new PMD values. + */ + ovfl_regs = ctx->ctx_ovfl_regs[0]; + + if (ctx->ctx_fl_going_zombie) { +do_zombie: + DPRINT(("context is zombie, bailing out\n")); + pfm_context_force_terminate(ctx, regs); + goto nothing_to_do; + } + /* + * in case of interruption of down() we don't restart anything + */ + if (ret < 0) goto nothing_to_do; + +skip_blocking: + pfm_resume_after_ovfl(ctx, ovfl_regs, regs); + ctx->ctx_ovfl_regs[0] = 0UL; + +nothing_to_do: + /* + * restore flags as they were upon entry + */ + UNPROTECT_CTX(ctx, flags); +} + +static int +pfm_notify_user(pfm_context_t *ctx, pfm_msg_t *msg) +{ + if (ctx->ctx_state == PFM_CTX_ZOMBIE) { + DPRINT(("ignoring overflow notification, owner is zombie\n")); + return 0; + } + + DPRINT(("waking up somebody\n")); + + if (msg) wake_up_interruptible(&ctx->ctx_msgq_wait); + + /* + * safe, we are not in intr handler, nor in ctxsw when + * we come here + */ + kill_fasync (&ctx->ctx_async_queue, SIGIO, POLL_IN); + + return 0; +} + +static int +pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds) +{ + pfm_msg_t *msg = NULL; + + if (ctx->ctx_fl_no_msg == 0) { + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_ovfl_notify_user no more notification msgs\n"); + return -1; + } + + msg->pfm_ovfl_msg.msg_type = PFM_MSG_OVFL; + msg->pfm_ovfl_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_active_set = 0; + msg->pfm_ovfl_msg.msg_ovfl_pmds[0] = ovfl_pmds; + msg->pfm_ovfl_msg.msg_ovfl_pmds[1] = 0UL; + msg->pfm_ovfl_msg.msg_ovfl_pmds[2] = 0UL; + msg->pfm_ovfl_msg.msg_ovfl_pmds[3] = 0UL; + msg->pfm_ovfl_msg.msg_tstamp = 0UL; + } + + DPRINT(("ovfl msg: msg=%p no_msg=%d fd=%d ovfl_pmds=0x%lx\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd, + ovfl_pmds)); + + return pfm_notify_user(ctx, msg); +} + +static int +pfm_end_notify_user(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_end_notify_user no more notification msgs\n"); + return -1; + } + /* no leak */ + memset(msg, 0, sizeof(*msg)); + + msg->pfm_end_msg.msg_type = PFM_MSG_END; + msg->pfm_end_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_tstamp = 0UL; + + DPRINT(("end msg: msg=%p no_msg=%d ctx_fd=%d\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd)); + + return pfm_notify_user(ctx, msg); +} + +/* + * main overflow processing routine. + * it can be called from the interrupt path or explicitely during the context switch code + */ +static void +pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +{ + pfm_ovfl_arg_t *ovfl_arg; + unsigned long mask; + unsigned long old_val, ovfl_val, new_val; + unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL, reset_pmds; + unsigned long tstamp; + pfm_ovfl_ctrl_t ovfl_ctrl; + unsigned int i, has_smpl; + int must_notify = 0; + + if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) goto stop_monitoring; + + /* + * sanity test. Should never happen + */ + if (unlikely((pmc0 & 0x1) == 0)) goto sanity_check; + + tstamp = ia64_get_itc(); + mask = pmc0 >> PMU_FIRST_COUNTER; + ovfl_val = pmu_conf->ovfl_val; + has_smpl = CTX_HAS_SMPL(ctx); + + DPRINT_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s " + "used_pmds=0x%lx\n", + pmc0, + task ? task->pid: -1, + (regs ? regs->cr_iip : 0), + CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", + ctx->ctx_used_pmds[0])); + + + /* + * first we update the virtual counters + * assume there was a prior ia64_srlz_d() issued + */ + for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) { + + /* skip pmd which did not overflow */ + if ((mask & 0x1) == 0) continue; + + /* + * Note that the pmd is not necessarily 0 at this point as qualified events + * may have happened before the PMU was frozen. The residual count is not + * taken into consideration here but will be with any read of the pmd via + * pfm_read_pmds(). + */ + old_val = new_val = ctx->ctx_pmds[i].val; + new_val += 1 + ovfl_val; + ctx->ctx_pmds[i].val = new_val; + + /* + * check for overflow condition + */ + if (likely(old_val > new_val)) { + ovfl_pmds |= 1UL << i; + if (PMC_OVFL_NOTIFY(ctx, i)) ovfl_notify |= 1UL << i; + } + + DPRINT_ovfl(("ctx_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", + i, + new_val, + old_val, + ia64_get_pmd(i) & ovfl_val, + ovfl_pmds, + ovfl_notify)); + } + + /* + * there was no 64-bit overflow, nothing else to do + */ + if (ovfl_pmds == 0UL) return; + + /* + * reset all control bits + */ + ovfl_ctrl.val = 0; + reset_pmds = 0UL; + + /* + * if a sampling format module exists, then we "cache" the overflow by + * calling the module's handler() routine. + */ + if (has_smpl) { + unsigned long start_cycles, end_cycles; + unsigned long pmd_mask; + int j, k, ret = 0; + int this_cpu = smp_processor_id(); + + pmd_mask = ovfl_pmds >> PMU_FIRST_COUNTER; + ovfl_arg = &ctx->ctx_ovfl_arg; + + prefetch(ctx->ctx_smpl_hdr); + + for(i=PMU_FIRST_COUNTER; pmd_mask && ret == 0; i++, pmd_mask >>=1) { + + mask = 1UL << i; + + if ((pmd_mask & 0x1) == 0) continue; + + ovfl_arg->ovfl_pmd = (unsigned char )i; + ovfl_arg->ovfl_notify = ovfl_notify & mask ? 1 : 0; + ovfl_arg->active_set = 0; + ovfl_arg->ovfl_ctrl.val = 0; /* module must fill in all fields */ + ovfl_arg->smpl_pmds[0] = smpl_pmds = ctx->ctx_pmds[i].smpl_pmds[0]; + + ovfl_arg->pmd_value = ctx->ctx_pmds[i].val; + ovfl_arg->pmd_last_reset = ctx->ctx_pmds[i].lval; + ovfl_arg->pmd_eventid = ctx->ctx_pmds[i].eventid; + + /* + * copy values of pmds of interest. Sampling format may copy them + * into sampling buffer. + */ + if (smpl_pmds) { + for(j=0, k=0; smpl_pmds; j++, smpl_pmds >>=1) { + if ((smpl_pmds & 0x1) == 0) continue; + ovfl_arg->smpl_pmds_values[k++] = PMD_IS_COUNTING(j) ? pfm_read_soft_counter(ctx, j) : ia64_get_pmd(j); + DPRINT_ovfl(("smpl_pmd[%d]=pmd%u=0x%lx\n", k-1, j, ovfl_arg->smpl_pmds_values[k-1])); + } + } + + pfm_stats[this_cpu].pfm_smpl_handler_calls++; + + start_cycles = ia64_get_itc(); + + /* + * call custom buffer format record (handler) routine + */ + ret = (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, ovfl_arg, regs, tstamp); + + end_cycles = ia64_get_itc(); + + /* + * For those controls, we take the union because they have + * an all or nothing behavior. + */ + ovfl_ctrl.bits.notify_user |= ovfl_arg->ovfl_ctrl.bits.notify_user; + ovfl_ctrl.bits.block_task |= ovfl_arg->ovfl_ctrl.bits.block_task; + ovfl_ctrl.bits.mask_monitoring |= ovfl_arg->ovfl_ctrl.bits.mask_monitoring; + /* + * build the bitmask of pmds to reset now + */ + if (ovfl_arg->ovfl_ctrl.bits.reset_ovfl_pmds) reset_pmds |= mask; + + pfm_stats[this_cpu].pfm_smpl_handler_cycles += end_cycles - start_cycles; + } + /* + * when the module cannot handle the rest of the overflows, we abort right here + */ + if (ret && pmd_mask) { + DPRINT(("handler aborts leftover ovfl_pmds=0x%lx\n", + pmd_mask<ctx_ovfl_regs[0] = ovfl_pmds; + + /* + * check for blocking context + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && ovfl_ctrl.bits.block_task) { + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCK; + + /* + * set the perfmon specific checking pending work for the task + */ + PFM_SET_WORK_PENDING(task, 1); + + /* + * when coming from ctxsw, current still points to the + * previous task, therefore we must work with task and not current. + */ + pfm_set_task_notify(task); + } + /* + * defer until state is changed (shorten spin window). the context is locked + * anyway, so the signal receiver would come spin for nothing. + */ + must_notify = 1; + } + + DPRINT_ovfl(("owner [%d] pending=%ld reason=%u ovfl_pmds=0x%lx ovfl_notify=0x%lx masked=%d\n", + GET_PMU_OWNER() ? GET_PMU_OWNER()->pid : -1, + PFM_GET_WORK_PENDING(task), + ctx->ctx_fl_trap_reason, + ovfl_pmds, + ovfl_notify, + ovfl_ctrl.bits.mask_monitoring ? 1 : 0)); + /* + * in case monitoring must be stopped, we toggle the psr bits + */ + if (ovfl_ctrl.bits.mask_monitoring) { + pfm_mask_monitoring(task); + ctx->ctx_state = PFM_CTX_MASKED; + ctx->ctx_fl_can_restart = 1; + } + + /* + * send notification now + */ + if (must_notify) pfm_ovfl_notify_user(ctx, ovfl_notify); + + return; + +sanity_check: + printk(KERN_ERR "perfmon: CPU%d overflow handler [%d] pmc0=0x%lx\n", + smp_processor_id(), + task ? task->pid : -1, + pmc0); + return; + +stop_monitoring: + /* + * in SMP, zombie context is never restored but reclaimed in pfm_load_regs(). + * Moreover, zombies are also reclaimed in pfm_save_regs(). Therefore we can + * come here as zombie only if the task is the current task. In which case, we + * can access the PMU hardware directly. + * + * Note that zombies do have PM_VALID set. So here we do the minimal. + * + * In case the context was zombified it could not be reclaimed at the time + * the monitoring program exited. At this point, the PMU reservation has been + * returned, the sampiing buffer has been freed. We must convert this call + * into a spurious interrupt. However, we must also avoid infinite overflows + * by stopping monitoring for this task. We can only come here for a per-task + * context. All we need to do is to stop monitoring using the psr bits which + * are always task private. By re-enabling secure montioring, we ensure that + * the monitored task will not be able to re-activate monitoring. + * The task will eventually be context switched out, at which point the context + * will be reclaimed (that includes releasing ownership of the PMU). + * + * So there might be a window of time where the number of per-task session is zero + * yet one PMU might have a owner and get at most one overflow interrupt for a zombie + * context. This is safe because if a per-task session comes in, it will push this one + * out and by the virtue on pfm_save_regs(), this one will disappear. If a system wide + * session is force on that CPU, given that we use task pinning, pfm_save_regs() will + * also push our zombie context out. + * + * Overall pretty hairy stuff.... + */ + DPRINT(("ctx is zombie for [%d], converted to spurious\n", task ? task->pid: -1)); + pfm_clear_psr_up(); + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + return; +} + +static int +pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + struct task_struct *task; + pfm_context_t *ctx; + unsigned long flags; + u64 pmc0; + int this_cpu = smp_processor_id(); + int retval = 0; + + pfm_stats[this_cpu].pfm_ovfl_intr_count++; + + /* + * srlz.d done before arriving here + */ + pmc0 = ia64_get_pmc(0); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + /* + * if we have some pending bits set + * assumes : if any PMC0.bit[63-1] is set, then PMC0.fr = 1 + */ + if (PMC0_HAS_OVFL(pmc0) && task) { + /* + * we assume that pmc0.fr is always set here + */ + + /* sanity check */ + if (!ctx) goto report_spurious1; + + if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) + goto report_spurious2; + + PROTECT_CTX_NOPRINT(ctx, flags); + + pfm_overflow_handler(task, ctx, pmc0, regs); + + UNPROTECT_CTX_NOPRINT(ctx, flags); + + } else { + pfm_stats[this_cpu].pfm_spurious_ovfl_intr_count++; + retval = -1; + } + /* + * keep it unfrozen at all times + */ + pfm_unfreeze_pmu(); + + return retval; + +report_spurious1: + printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n", + this_cpu, task->pid); + pfm_unfreeze_pmu(); + return -1; +report_spurious2: + printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d, invalid flag\n", + this_cpu, + task->pid); + pfm_unfreeze_pmu(); + return -1; +} + +static irqreturn_t +pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + unsigned long start_cycles, total_cycles; + unsigned long min, max; + int this_cpu; + int ret; + + this_cpu = get_cpu(); + if (likely(!pfm_alt_intr_handler)) { + min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; + max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; + + start_cycles = ia64_get_itc(); + + ret = pfm_do_interrupt_handler(irq, arg, regs); + + total_cycles = ia64_get_itc(); + + /* + * don't measure spurious interrupts + */ + if (likely(ret == 0)) { + total_cycles -= start_cycles; + + if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles; + if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles; + + pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles; + } + } + else { + (*pfm_alt_intr_handler->handler)(irq, arg, regs); + } + + put_cpu_no_resched(); + return IRQ_HANDLED; +} + +/* + * /proc/perfmon interface, for debug only + */ + +#define PFM_PROC_SHOW_HEADER ((void *)NR_CPUS+1) + +static void * +pfm_proc_start(struct seq_file *m, loff_t *pos) +{ + if (*pos == 0) { + return PFM_PROC_SHOW_HEADER; + } + + while (*pos <= NR_CPUS) { + if (cpu_online(*pos - 1)) { + return (void *)*pos; + } + ++*pos; + } + return NULL; +} + +static void * +pfm_proc_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return pfm_proc_start(m, pos); +} + +static void +pfm_proc_stop(struct seq_file *m, void *v) +{ +} + +static void +pfm_proc_show_header(struct seq_file *m) +{ + struct list_head * pos; + pfm_buffer_fmt_t * entry; + unsigned long flags; + + seq_printf(m, + "perfmon version : %u.%u\n" + "model : %s\n" + "fastctxsw : %s\n" + "expert mode : %s\n" + "ovfl_mask : 0x%lx\n" + "PMU flags : 0x%x\n", + PFM_VERSION_MAJ, PFM_VERSION_MIN, + pmu_conf->pmu_name, + pfm_sysctl.fastctxsw > 0 ? "Yes": "No", + pfm_sysctl.expert_mode > 0 ? "Yes": "No", + pmu_conf->ovfl_val, + pmu_conf->flags); + + LOCK_PFS(flags); + + seq_printf(m, + "proc_sessions : %u\n" + "sys_sessions : %u\n" + "sys_use_dbregs : %u\n" + "ptrace_use_dbregs : %u\n", + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_sys_use_dbregs, + pfm_sessions.pfs_ptrace_use_dbregs); + + UNLOCK_PFS(flags); + + spin_lock(&pfm_buffer_fmt_lock); + + list_for_each(pos, &pfm_buffer_fmt_list) { + entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list); + seq_printf(m, "format : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n", + entry->fmt_uuid[0], + entry->fmt_uuid[1], + entry->fmt_uuid[2], + entry->fmt_uuid[3], + entry->fmt_uuid[4], + entry->fmt_uuid[5], + entry->fmt_uuid[6], + entry->fmt_uuid[7], + entry->fmt_uuid[8], + entry->fmt_uuid[9], + entry->fmt_uuid[10], + entry->fmt_uuid[11], + entry->fmt_uuid[12], + entry->fmt_uuid[13], + entry->fmt_uuid[14], + entry->fmt_uuid[15], + entry->fmt_name); + } + spin_unlock(&pfm_buffer_fmt_lock); + +} + +static int +pfm_proc_show(struct seq_file *m, void *v) +{ + unsigned long psr; + unsigned int i; + int cpu; + + if (v == PFM_PROC_SHOW_HEADER) { + pfm_proc_show_header(m); + return 0; + } + + /* show info for CPU (v - 1) */ + + cpu = (long)v - 1; + seq_printf(m, + "CPU%-2d overflow intrs : %lu\n" + "CPU%-2d overflow cycles : %lu\n" + "CPU%-2d overflow min : %lu\n" + "CPU%-2d overflow max : %lu\n" + "CPU%-2d smpl handler calls : %lu\n" + "CPU%-2d smpl handler cycles : %lu\n" + "CPU%-2d spurious intrs : %lu\n" + "CPU%-2d replay intrs : %lu\n" + "CPU%-2d syst_wide : %d\n" + "CPU%-2d dcr_pp : %d\n" + "CPU%-2d exclude idle : %d\n" + "CPU%-2d owner : %d\n" + "CPU%-2d context : %p\n" + "CPU%-2d activations : %lu\n", + cpu, pfm_stats[cpu].pfm_ovfl_intr_count, + cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles, + cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles_min, + cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles_max, + cpu, pfm_stats[cpu].pfm_smpl_handler_calls, + cpu, pfm_stats[cpu].pfm_smpl_handler_cycles, + cpu, pfm_stats[cpu].pfm_spurious_ovfl_intr_count, + cpu, pfm_stats[cpu].pfm_replay_ovfl_intr_count, + cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_SYST_WIDE ? 1 : 0, + cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_DCR_PP ? 1 : 0, + cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0, + cpu, pfm_get_cpu_data(pmu_owner, cpu) ? pfm_get_cpu_data(pmu_owner, cpu)->pid: -1, + cpu, pfm_get_cpu_data(pmu_ctx, cpu), + cpu, pfm_get_cpu_data(pmu_activation_number, cpu)); + + if (num_online_cpus() == 1 && pfm_sysctl.debug > 0) { + + psr = pfm_get_psr(); + + ia64_srlz_d(); + + seq_printf(m, + "CPU%-2d psr : 0x%lx\n" + "CPU%-2d pmc0 : 0x%lx\n", + cpu, psr, + cpu, ia64_get_pmc(0)); + + for (i=0; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_COUNTING(i) == 0) continue; + seq_printf(m, + "CPU%-2d pmc%u : 0x%lx\n" + "CPU%-2d pmd%u : 0x%lx\n", + cpu, i, ia64_get_pmc(i), + cpu, i, ia64_get_pmd(i)); + } + } + return 0; +} + +struct seq_operations pfm_seq_ops = { + .start = pfm_proc_start, + .next = pfm_proc_next, + .stop = pfm_proc_stop, + .show = pfm_proc_show +}; + +static int +pfm_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pfm_seq_ops); +} + + +/* + * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens + * during pfm_enable() hence before pfm_start(). We cannot assume monitoring + * is active or inactive based on mode. We must rely on the value in + * local_cpu_data->pfm_syst_info + */ +void +pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) +{ + struct pt_regs *regs; + unsigned long dcr; + unsigned long dcr_pp; + + dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0; + + /* + * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 + * on every CPU, so we can rely on the pid to identify the idle task. + */ + if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) { + regs = task_pt_regs(task); + ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0; + return; + } + /* + * if monitoring has started + */ + if (dcr_pp) { + dcr = ia64_getreg(_IA64_REG_CR_DCR); + /* + * context switching in? + */ + if (is_ctxswin) { + /* mask monitoring for the idle task */ + ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + ia64_srlz_i(); + return; + } + /* + * context switching out + * restore monitoring for next task + * + * Due to inlining this odd if-then-else construction generates + * better code. + */ + ia64_setreg(_IA64_REG_CR_DCR, dcr |IA64_DCR_PP); + pfm_set_psr_pp(); + ia64_srlz_i(); + } +} + +#ifdef CONFIG_SMP + +static void +pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs) +{ + struct task_struct *task = ctx->ctx_task; + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + + if (GET_PMU_OWNER() == task) { + DPRINT(("cleared ownership for [%d]\n", ctx->ctx_task->pid)); + SET_PMU_OWNER(NULL, NULL); + } + + /* + * disconnect the task from the context and vice-versa + */ + PFM_SET_WORK_PENDING(task, 0); + + task->thread.pfm_context = NULL; + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + DPRINT(("force cleanup for [%d]\n", task->pid)); +} + + +/* + * in 2.6, interrupts are masked when we come here and the runqueue lock is held + */ +void +pfm_save_regs(struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + u64 psr; + + + ctx = PFM_GET_CTX(task); + if (ctx == NULL) return; + t = &task->thread; + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + + if (ctx->ctx_state == PFM_CTX_ZOMBIE) { + struct pt_regs *regs = task_pt_regs(task); + + pfm_clear_psr_up(); + + pfm_force_cleanup(ctx, regs); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + pfm_context_free(ctx); + return; + } + + /* + * save current PSR: needed because we modify it + */ + ia64_srlz_d(); + psr = pfm_get_psr(); + + BUG_ON(psr & (IA64_PSR_I)); + + /* + * stop monitoring: + * This is the last instruction which may generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level + */ + pfm_clear_psr_up(); + + /* + * keep a copy of psr.up (for reload) + */ + ctx->ctx_saved_psr_up = psr & IA64_PSR_UP; + + /* + * release ownership of this PMU. + * PM interrupts are masked, so nothing + * can happen. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * we systematically save the PMD as we have no + * guarantee we will be schedule at that same + * CPU again. + */ + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); + + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * we will need it on the restore path to check + * for pending overflow. + */ + t->pmcs[0] = ia64_get_pmc(0); + + /* + * unfreeze PMU if had pending overflows + */ + if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu(); + + /* + * finally, allow context access. + * interrupts will still be masked after this call. + */ + pfm_unprotect_ctx_ctxsw(ctx, flags); +} + +#else /* !CONFIG_SMP */ +void +pfm_save_regs(struct task_struct *task) +{ + pfm_context_t *ctx; + u64 psr; + + ctx = PFM_GET_CTX(task); + if (ctx == NULL) return; + + /* + * save current PSR: needed because we modify it + */ + psr = pfm_get_psr(); + + BUG_ON(psr & (IA64_PSR_I)); + + /* + * stop monitoring: + * This is the last instruction which may generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level + */ + pfm_clear_psr_up(); + + /* + * keep a copy of psr.up (for reload) + */ + ctx->ctx_saved_psr_up = psr & IA64_PSR_UP; +} + +static void +pfm_lazy_save_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + + { u64 psr = pfm_get_psr(); + BUG_ON(psr & IA64_PSR_UP); + } + + ctx = PFM_GET_CTX(task); + t = &task->thread; + + /* + * we need to mask PMU overflow here to + * make sure that we maintain pmc0 until + * we save it. overflow interrupts are + * treated as spurious if there is no + * owner. + * + * XXX: I don't think this is necessary + */ + PROTECT_CTX(ctx,flags); + + /* + * release ownership of this PMU. + * must be done before we save the registers. + * + * after this call any PMU interrupt is treated + * as spurious. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * save all the pmds we use + */ + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); + + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * it is needed to check for pended overflow + * on the restore path + */ + t->pmcs[0] = ia64_get_pmc(0); + + /* + * unfreeze PMU if had pending overflows + */ + if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu(); + + /* + * now get can unmask PMU interrupts, they will + * be treated as purely spurious and we will not + * lose any information + */ + UNPROTECT_CTX(ctx,flags); +} +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_SMP +/* + * in 2.6, interrupts are masked when we come here and the runqueue lock is held + */ +void +pfm_load_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long pmc_mask = 0UL, pmd_mask = 0UL; + unsigned long flags; + u64 psr, psr_up; + int need_irq_resend; + + ctx = PFM_GET_CTX(task); + if (unlikely(ctx == NULL)) return; + + BUG_ON(GET_PMU_OWNER()); + + t = &task->thread; + /* + * possible on unload + */ + if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) return; + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + psr = pfm_get_psr(); + + need_irq_resend = pmu_conf->flags & PFM_PMU_IRQ_RESEND; + + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + BUG_ON(psr & IA64_PSR_I); + + if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) { + struct pt_regs *regs = task_pt_regs(task); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_force_cleanup(ctx, regs); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + /* + * this one (kmalloc'ed) is fine with interrupts disabled + */ + pfm_context_free(ctx); + + return; + } + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + /* + * retrieve saved psr.up + */ + psr_up = ctx->ctx_saved_psr_up; + + /* + * if we were the last user of the PMU on that CPU, + * then nothing to do except restore psr + */ + if (GET_LAST_CPU(ctx) == smp_processor_id() && ctx->ctx_last_activation == GET_ACTIVATION()) { + + /* + * retrieve partial reload masks (due to user modifications) + */ + pmc_mask = ctx->ctx_reload_pmcs[0]; + pmd_mask = ctx->ctx_reload_pmds[0]; + + } else { + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately. + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + } + /* + * when context is MASKED, we will restore PMC with plm=0 + * and PMD with stale information, but that's ok, nothing + * will be captured. + * + * XXX: optimize here + */ + if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask); + if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask); + + /* + * check for pending overflow at the time the state + * was saved. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + /* + * reload pmc0 with the overflow information + * On McKinley PMU, this will trigger a PMU interrupt + */ + ia64_set_pmc(0, t->pmcs[0]); + ia64_srlz_d(); + t->pmcs[0] = 0UL; + + /* + * will replay the PMU interrupt + */ + if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR); + + pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++; + } + + /* + * we just did a reload, so we reset the partial reload fields + */ + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + SET_LAST_CPU(ctx, smp_processor_id()); + + /* + * dump activation value for this PMU + */ + INC_ACTIVATION(); + /* + * record current activation for this context + */ + SET_ACTIVATION(ctx); + + /* + * establish new ownership. + */ + SET_PMU_OWNER(task, ctx); + + /* + * restore the psr.up bit. measurement + * is active again. + * no PMU interrupt can happen at this point + * because we still have interrupts disabled. + */ + if (likely(psr_up)) pfm_set_psr_up(); + + /* + * allow concurrent access to context + */ + pfm_unprotect_ctx_ctxsw(ctx, flags); +} +#else /* !CONFIG_SMP */ +/* + * reload PMU state for UP kernels + * in 2.5 we come here with interrupts disabled + */ +void +pfm_load_regs (struct task_struct *task) +{ + struct thread_struct *t; + pfm_context_t *ctx; + struct task_struct *owner; + unsigned long pmd_mask, pmc_mask; + u64 psr, psr_up; + int need_irq_resend; + + owner = GET_PMU_OWNER(); + ctx = PFM_GET_CTX(task); + t = &task->thread; + psr = pfm_get_psr(); + + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + BUG_ON(psr & IA64_PSR_I); + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + * + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + + /* + * retrieved saved psr.up + */ + psr_up = ctx->ctx_saved_psr_up; + need_irq_resend = pmu_conf->flags & PFM_PMU_IRQ_RESEND; + + /* + * short path, our state is still there, just + * need to restore psr and we go + * + * we do not touch either PMC nor PMD. the psr is not touched + * by the overflow_handler. So we are safe w.r.t. to interrupt + * concurrency even without interrupt masking. + */ + if (likely(owner == task)) { + if (likely(psr_up)) pfm_set_psr_up(); + return; + } + + /* + * someone else is still using the PMU, first push it out and + * then we'll be able to install our stuff ! + * + * Upon return, there will be no owner for the current PMU + */ + if (owner) pfm_lazy_save_regs(owner); + + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + + pfm_restore_pmds(t->pmds, pmd_mask); + pfm_restore_pmcs(t->pmcs, pmc_mask); + + /* + * check for pending overflow at the time the state + * was saved. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + /* + * reload pmc0 with the overflow information + * On McKinley PMU, this will trigger a PMU interrupt + */ + ia64_set_pmc(0, t->pmcs[0]); + ia64_srlz_d(); + + t->pmcs[0] = 0UL; + + /* + * will replay the PMU interrupt + */ + if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR); + + pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++; + } + + /* + * establish new ownership. + */ + SET_PMU_OWNER(task, ctx); + + /* + * restore the psr.up bit. measurement + * is active again. + * no PMU interrupt can happen at this point + * because we still have interrupts disabled. + */ + if (likely(psr_up)) pfm_set_psr_up(); +} +#endif /* CONFIG_SMP */ + +/* + * this function assumes monitoring is stopped + */ +static void +pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + u64 pmc0; + unsigned long mask2, val, pmd_val, ovfl_val; + int i, can_access_pmu = 0; + int is_self; + + /* + * is the caller the task being monitored (or which initiated the + * session for system wide measurements) + */ + is_self = ctx->ctx_task == task ? 1 : 0; + + /* + * can access PMU is task is the owner of the PMU state on the current CPU + * or if we are running on the CPU bound to the context in system-wide mode + * (that is not necessarily the task the context is attached to in this mode). + * In system-wide we always have can_access_pmu true because a task running on an + * invalid processor is flagged earlier in the call stack (see pfm_stop). + */ + can_access_pmu = (GET_PMU_OWNER() == task) || (ctx->ctx_fl_system && ctx->ctx_cpu == smp_processor_id()); + if (can_access_pmu) { + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control on overflow processing from that point + * on. + */ + SET_PMU_OWNER(NULL, NULL); + DPRINT(("releasing ownership\n")); + + /* + * read current overflow status: + * + * we are guaranteed to read the final stable state + */ + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * reset freeze bit, overflow status information destroyed + */ + pfm_unfreeze_pmu(); + } else { + pmc0 = task->thread.pmcs[0]; + /* + * clear whatever overflow status bits there were + */ + task->thread.pmcs[0] = 0; + } + ovfl_val = pmu_conf->ovfl_val; + /* + * we save all the used pmds + * we take care of overflows for counting PMDs + * + * XXX: sampling situation is not taken into account here + */ + mask2 = ctx->ctx_used_pmds[0]; + + DPRINT(("is_self=%d ovfl_val=0x%lx mask2=0x%lx\n", is_self, ovfl_val, mask2)); + + for (i = 0; mask2; i++, mask2>>=1) { + + /* skip non used pmds */ + if ((mask2 & 0x1) == 0) continue; + + /* + * can access PMU always true in system wide mode + */ + val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i]; + + if (PMD_IS_COUNTING(i)) { + DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n", + task->pid, + i, + ctx->ctx_pmds[i].val, + val & ovfl_val)); + + /* + * we rebuild the full 64 bit value of the counter + */ + val = ctx->ctx_pmds[i].val + (val & ovfl_val); + + /* + * now everything is in ctx_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value + */ + pmd_val = 0UL; + + /* + * take care of overflow inline + */ + if (pmc0 & (1UL << i)) { + val += 1 + ovfl_val; + DPRINT(("[%d] pmd[%d] overflowed\n", task->pid, i)); + } + } + + DPRINT(("[%d] ctx_pmd[%d]=0x%lx pmd_val=0x%lx\n", task->pid, i, val, pmd_val)); + + if (is_self) task->thread.pmds[i] = pmd_val; + + ctx->ctx_pmds[i].val = val; + } +} + +static struct irqaction perfmon_irqaction = { + .handler = pfm_interrupt_handler, + .flags = SA_INTERRUPT, + .name = "perfmon" +}; + +static void +pfm_alt_save_pmu_state(void *data) +{ + struct pt_regs *regs; + + regs = task_pt_regs(current); + + DPRINT(("called\n")); + + /* + * should not be necessary but + * let's take not risk + */ + pfm_clear_psr_up(); + pfm_clear_psr_pp(); + ia64_psr(regs)->pp = 0; + + /* + * This call is required + * May cause a spurious interrupt on some processors + */ + pfm_freeze_pmu(); + + ia64_srlz_d(); +} + +void +pfm_alt_restore_pmu_state(void *data) +{ + struct pt_regs *regs; + + regs = task_pt_regs(current); + + DPRINT(("called\n")); + + /* + * put PMU back in state expected + * by perfmon + */ + pfm_clear_psr_up(); + pfm_clear_psr_pp(); + ia64_psr(regs)->pp = 0; + + /* + * perfmon runs with PMU unfrozen at all times + */ + pfm_unfreeze_pmu(); + + ia64_srlz_d(); +} + +int +pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) +{ + int ret, i; + int reserve_cpu; + + /* some sanity checks */ + if (hdl == NULL || hdl->handler == NULL) return -EINVAL; + + /* do the easy test first */ + if (pfm_alt_intr_handler) return -EBUSY; + + /* one at a time in the install or remove, just fail the others */ + if (!spin_trylock(&pfm_alt_install_check)) { + return -EBUSY; + } + + /* reserve our session */ + for_each_online_cpu(reserve_cpu) { + ret = pfm_reserve_session(NULL, 1, reserve_cpu); + if (ret) goto cleanup_reserve; + } + + /* save the current system wide pmu states */ + ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 0, 1); + if (ret) { + DPRINT(("on_each_cpu() failed: %d\n", ret)); + goto cleanup_reserve; + } + + /* officially change to the alternate interrupt handler */ + pfm_alt_intr_handler = hdl; + + spin_unlock(&pfm_alt_install_check); + + return 0; + +cleanup_reserve: + for_each_online_cpu(i) { + /* don't unreserve more than we reserved */ + if (i >= reserve_cpu) break; + + pfm_unreserve_session(NULL, 1, i); + } + + spin_unlock(&pfm_alt_install_check); + + return ret; +} +EXPORT_SYMBOL_GPL(pfm_install_alt_pmu_interrupt); + +int +pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) +{ + int i; + int ret; + + if (hdl == NULL) return -EINVAL; + + /* cannot remove someone else's handler! */ + if (pfm_alt_intr_handler != hdl) return -EINVAL; + + /* one at a time in the install or remove, just fail the others */ + if (!spin_trylock(&pfm_alt_install_check)) { + return -EBUSY; + } + + pfm_alt_intr_handler = NULL; + + ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 0, 1); + if (ret) { + DPRINT(("on_each_cpu() failed: %d\n", ret)); + } + + for_each_online_cpu(i) { + pfm_unreserve_session(NULL, 1, i); + } + + spin_unlock(&pfm_alt_install_check); + + return 0; +} +EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt); + +/* + * perfmon initialization routine, called from the initcall() table + */ +static int init_pfm_fs(void); + +static int __init +pfm_probe_pmu(void) +{ + pmu_config_t **p; + int family; + + family = local_cpu_data->family; + p = pmu_confs; + + while(*p) { + if ((*p)->probe) { + if ((*p)->probe() == 0) goto found; + } else if ((*p)->pmu_family == family || (*p)->pmu_family == 0xff) { + goto found; + } + p++; + } + return -1; +found: + pmu_conf = *p; + return 0; +} + +static struct file_operations pfm_proc_fops = { + .open = pfm_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int __init +pfm_init(void) +{ + unsigned int n, n_counters, i; + + printk("perfmon: version %u.%u IRQ %u\n", + PFM_VERSION_MAJ, + PFM_VERSION_MIN, + IA64_PERFMON_VECTOR); + + if (pfm_probe_pmu()) { + printk(KERN_INFO "perfmon: disabled, there is no support for processor family %d\n", + local_cpu_data->family); + return -ENODEV; + } + + /* + * compute the number of implemented PMD/PMC from the + * description tables + */ + n = 0; + for (i=0; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + pmu_conf->impl_pmcs[i>>6] |= 1UL << (i&63); + n++; + } + pmu_conf->num_pmcs = n; + + n = 0; n_counters = 0; + for (i=0; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + pmu_conf->impl_pmds[i>>6] |= 1UL << (i&63); + n++; + if (PMD_IS_COUNTING(i)) n_counters++; + } + pmu_conf->num_pmds = n; + pmu_conf->num_counters = n_counters; + + /* + * sanity checks on the number of debug registers + */ + if (pmu_conf->use_rr_dbregs) { + if (pmu_conf->num_ibrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of code debug registers (%u)\n", pmu_conf->num_ibrs); + pmu_conf = NULL; + return -1; + } + if (pmu_conf->num_dbrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of data debug registers (%u)\n", pmu_conf->num_ibrs); + pmu_conf = NULL; + return -1; + } + } + + printk("perfmon: %s PMU detected, %u PMCs, %u PMDs, %u counters (%lu bits)\n", + pmu_conf->pmu_name, + pmu_conf->num_pmcs, + pmu_conf->num_pmds, + pmu_conf->num_counters, + ffz(pmu_conf->ovfl_val)); + + /* sanity check */ + if (pmu_conf->num_pmds >= IA64_NUM_PMD_REGS || pmu_conf->num_pmcs >= IA64_NUM_PMC_REGS) { + printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n"); + pmu_conf = NULL; + return -1; + } + + /* + * create /proc/perfmon (mostly for debugging purposes) + */ + perfmon_dir = create_proc_entry("perfmon", S_IRUGO, NULL); + if (perfmon_dir == NULL) { + printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); + pmu_conf = NULL; + return -1; + } + /* + * install customized file operations for /proc/perfmon entry + */ + perfmon_dir->proc_fops = &pfm_proc_fops; + + /* + * create /proc/sys/kernel/perfmon (for debugging purposes) + */ + pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); + + /* + * initialize all our spinlocks + */ + spin_lock_init(&pfm_sessions.pfs_lock); + spin_lock_init(&pfm_buffer_fmt_lock); + + init_pfm_fs(); + + for(i=0; i < NR_CPUS; i++) pfm_stats[i].pfm_ovfl_intr_cycles_min = ~0UL; + + return 0; +} + +__initcall(pfm_init); + +/* + * this function is called before pfm_init() + */ +void +pfm_init_percpu (void) +{ + /* + * make sure no measurement is active + * (may inherit programmed PMCs from EFI). + */ + pfm_clear_psr_pp(); + pfm_clear_psr_up(); + + /* + * we run with the PMU not frozen at all times + */ + pfm_unfreeze_pmu(); + + if (smp_processor_id() == 0) + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + + ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); + ia64_srlz_d(); +} + +/* + * used for debug purposes only + */ +void +dump_pmu_state(const char *from) +{ + struct task_struct *task; + struct thread_struct *t; + struct pt_regs *regs; + pfm_context_t *ctx; + unsigned long psr, dcr, info, flags; + int i, this_cpu; + + local_irq_save(flags); + + this_cpu = smp_processor_id(); + regs = task_pt_regs(current); + info = PFM_CPUINFO_GET(); + dcr = ia64_getreg(_IA64_REG_CR_DCR); + + if (info == 0 && ia64_psr(regs)->pp == 0 && (dcr & IA64_DCR_PP) == 0) { + local_irq_restore(flags); + return; + } + + printk("CPU%d from %s() current [%d] iip=0x%lx %s\n", + this_cpu, + from, + current->pid, + regs->cr_iip, + current->comm); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + printk("->CPU%d owner [%d] ctx=%p\n", this_cpu, task ? task->pid : -1, ctx); + + psr = pfm_get_psr(); + + printk("->CPU%d pmc0=0x%lx psr.pp=%d psr.up=%d dcr.pp=%d syst_info=0x%lx user_psr.up=%d user_psr.pp=%d\n", + this_cpu, + ia64_get_pmc(0), + psr & IA64_PSR_PP ? 1 : 0, + psr & IA64_PSR_UP ? 1 : 0, + dcr & IA64_DCR_PP ? 1 : 0, + info, + ia64_psr(regs)->up, + ia64_psr(regs)->pp); + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; + + t = ¤t->thread; + + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, t->pmcs[i]); + } + + for (i=1; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, t->pmds[i]); + } + + if (ctx) { + printk("->CPU%d ctx_state=%d vaddr=%p addr=%p fd=%d ctx_task=[%d] saved_psr_up=0x%lx\n", + this_cpu, + ctx->ctx_state, + ctx->ctx_smpl_vaddr, + ctx->ctx_smpl_hdr, + ctx->ctx_msgq_head, + ctx->ctx_msgq_tail, + ctx->ctx_saved_psr_up); + } + local_irq_restore(flags); +} + +/* + * called from process.c:copy_thread(). task is new child. + */ +void +pfm_inherit(struct task_struct *task, struct pt_regs *regs) +{ + struct thread_struct *thread; + + DPRINT(("perfmon: pfm_inherit clearing state for [%d]\n", task->pid)); + + thread = &task->thread; + + /* + * cut links inherited from parent (current) + */ + thread->pfm_context = NULL; + + PFM_SET_WORK_PENDING(task, 0); + + /* + * the psr bits are already set properly in copy_threads() + */ +} +#else /* !CONFIG_PERFMON */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void *arg, int count) +{ + return -ENOSYS; +} +#endif /* CONFIG_PERFMON */ diff --git a/xen/arch/ia64/linux-xen/perfmon_default_smpl.c b/xen/arch/ia64/linux-xen/perfmon_default_smpl.c new file mode 100644 index 0000000000..344941db0a --- /dev/null +++ b/xen/arch/ia64/linux-xen/perfmon_default_smpl.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2002-2003 Hewlett-Packard Co + * Stephane Eranian + * + * This file implements the default sampling buffer format + * for the Linux/ia64 perfmon-2 subsystem. + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Stephane Eranian "); +MODULE_DESCRIPTION("perfmon default sampling format"); +MODULE_LICENSE("GPL"); + +#define DEFAULT_DEBUG 1 + +#ifdef DEFAULT_DEBUG +#define DPRINT(a) \ + do { \ + if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#define DPRINT_ovfl(a) \ + do { \ + if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __FUNCTION__, __LINE__, smp_processor_id()); printk a; } \ + } while (0) + +#else +#define DPRINT(a) +#define DPRINT_ovfl(a) +#endif + +static int +default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data) +{ + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data; + int ret = 0; + + if (data == NULL) { + DPRINT(("[%d] no argument passed\n", task->pid)); + return -EINVAL; + } + + DPRINT(("[%d] validate flags=0x%x CPU%d\n", task->pid, flags, cpu)); + + /* + * must hold at least the buffer header + one minimally sized entry + */ + if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL; + + DPRINT(("buf_size=%lu\n", arg->buf_size)); + + return ret; +} + +static int +default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size) +{ + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; + + /* + * size has been validated in default_validate + */ + *size = arg->buf_size; + + return 0; +} + +static int +default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data) +{ + pfm_default_smpl_hdr_t *hdr; + pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data; + + hdr = (pfm_default_smpl_hdr_t *)buf; + + hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION; + hdr->hdr_buf_size = arg->buf_size; + hdr->hdr_cur_offs = sizeof(*hdr); + hdr->hdr_overflows = 0UL; + hdr->hdr_count = 0UL; + + DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u cur_offs=%lu\n", + task->pid, + buf, + hdr->hdr_buf_size, + sizeof(*hdr), + hdr->hdr_version, + hdr->hdr_cur_offs)); + + return 0; +} + +static int +default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp) +{ + pfm_default_smpl_hdr_t *hdr; + pfm_default_smpl_entry_t *ent; + void *cur, *last; + unsigned long *e, entry_size; + unsigned int npmds, i; + unsigned char ovfl_pmd; + unsigned char ovfl_notify; + + if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) { + DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg)); + return -EINVAL; + } + + hdr = (pfm_default_smpl_hdr_t *)buf; + cur = buf+hdr->hdr_cur_offs; + last = buf+hdr->hdr_buf_size; + ovfl_pmd = arg->ovfl_pmd; + ovfl_notify = arg->ovfl_notify; + + /* + * precheck for sanity + */ + if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; + + npmds = hweight64(arg->smpl_pmds[0]); + + ent = (pfm_default_smpl_entry_t *)cur; + + prefetch(arg->smpl_pmds_values); + + entry_size = sizeof(*ent) + (npmds << 3); + + /* position for first pmd */ + e = (unsigned long *)(ent+1); + + hdr->hdr_count++; + + DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n", + task->pid, + hdr->hdr_count, + cur, last, + last-cur, + ovfl_pmd, + ovfl_notify, npmds)); + + /* + * current = task running at the time of the overflow. + * + * per-task mode: + * - this is ususally the task being monitored. + * Under certain conditions, it might be a different task + * + * system-wide: + * - this is not necessarily the task controlling the session + */ + ent->pid = current->pid; + ent->ovfl_pmd = ovfl_pmd; + ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val; + + /* + * where did the fault happen (includes slot number) + */ + ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3); + + ent->tstamp = stamp; + ent->cpu = smp_processor_id(); + ent->set = arg->active_set; + ent->tgid = current->tgid; + + /* + * selectively store PMDs in increasing index number + */ + if (npmds) { + unsigned long *val = arg->smpl_pmds_values; + for(i=0; i < npmds; i++) { + *e++ = *val++; + } + } + + /* + * update position for next entry + */ + hdr->hdr_cur_offs += entry_size; + cur += entry_size; + + /* + * post check to avoid losing the last sample + */ + if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full; + + /* + * keep same ovfl_pmds, ovfl_notify + */ + arg->ovfl_ctrl.bits.notify_user = 0; + arg->ovfl_ctrl.bits.block_task = 0; + arg->ovfl_ctrl.bits.mask_monitoring = 0; + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */ + + return 0; +full: + DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify)); + + /* + * increment number of buffer overflow. + * important to detect duplicate set of samples. + */ + hdr->hdr_overflows++; + + /* + * if no notification requested, then we saturate the buffer + */ + if (ovfl_notify == 0) { + arg->ovfl_ctrl.bits.notify_user = 0; + arg->ovfl_ctrl.bits.block_task = 0; + arg->ovfl_ctrl.bits.mask_monitoring = 1; + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; + } else { + arg->ovfl_ctrl.bits.notify_user = 1; + arg->ovfl_ctrl.bits.block_task = 1; /* ignored for non-blocking context */ + arg->ovfl_ctrl.bits.mask_monitoring = 1; + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */ + } + return -1; /* we are full, sorry */ +} + +static int +default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + pfm_default_smpl_hdr_t *hdr; + + hdr = (pfm_default_smpl_hdr_t *)buf; + + hdr->hdr_count = 0UL; + hdr->hdr_cur_offs = sizeof(*hdr); + + ctrl->bits.mask_monitoring = 0; + ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */ + + return 0; +} + +static int +default_exit(struct task_struct *task, void *buf, struct pt_regs *regs) +{ + DPRINT(("[%d] exit(%p)\n", task->pid, buf)); + return 0; +} + +static pfm_buffer_fmt_t default_fmt={ + .fmt_name = "default_format", + .fmt_uuid = PFM_DEFAULT_SMPL_UUID, + .fmt_arg_size = sizeof(pfm_default_smpl_arg_t), + .fmt_validate = default_validate, + .fmt_getsize = default_get_size, + .fmt_init = default_init, + .fmt_handler = default_handler, + .fmt_restart = default_restart, + .fmt_restart_active = default_restart, + .fmt_exit = default_exit, +}; + +static int __init +pfm_default_smpl_init_module(void) +{ + int ret; + + ret = pfm_register_buffer_fmt(&default_fmt); + if (ret == 0) { + printk("perfmon_default_smpl: %s v%u.%u registered\n", + default_fmt.fmt_name, + PFM_DEFAULT_SMPL_VERSION_MAJ, + PFM_DEFAULT_SMPL_VERSION_MIN); + } else { + printk("perfmon_default_smpl: %s cannot register ret=%d\n", + default_fmt.fmt_name, + ret); + } + + return ret; +} + +static void __exit +pfm_default_smpl_cleanup_module(void) +{ + int ret; + ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid); + + printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret); +} + +module_init(pfm_default_smpl_init_module); +module_exit(pfm_default_smpl_cleanup_module); + diff --git a/xen/arch/ia64/linux-xen/perfmon_generic.h b/xen/arch/ia64/linux-xen/perfmon_generic.h new file mode 100644 index 0000000000..6748947804 --- /dev/null +++ b/xen/arch/ia64/linux-xen/perfmon_generic.h @@ -0,0 +1,45 @@ +/* + * This file contains the generic PMU register description tables + * and pmc checker used by perfmon.c. + * + * Copyright (C) 2002-2003 Hewlett Packard Co + * Stephane Eranian + */ + +static pfm_reg_desc_t pfm_gen_pmc_desc[PMU_MAX_PMCS]={ +/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, + { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pfm_gen_pmd_desc[PMU_MAX_PMDS]={ +/* pmd0 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +/* pmd1 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +/* pmd2 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +/* pmd3 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, +/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, + { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +/* + * impl_pmcs, impl_pmds are computed at runtime to minimize errors! + */ +static pmu_config_t pmu_conf_gen={ + .pmu_name = "Generic", + .pmu_family = 0xff, /* any */ + .ovfl_val = (1UL << 32) - 1, + .num_ibrs = 0, /* does not use */ + .num_dbrs = 0, /* does not use */ + .pmd_desc = pfm_gen_pmd_desc, + .pmc_desc = pfm_gen_pmc_desc +}; + diff --git a/xen/arch/ia64/linux-xen/perfmon_itanium.h b/xen/arch/ia64/linux-xen/perfmon_itanium.h new file mode 100644 index 0000000000..d1d508a0fb --- /dev/null +++ b/xen/arch/ia64/linux-xen/perfmon_itanium.h @@ -0,0 +1,115 @@ +/* + * This file contains the Itanium PMU register description tables + * and pmc checker used by perfmon.c. + * + * Copyright (C) 2002-2003 Hewlett Packard Co + * Stephane Eranian + */ +static int pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + +static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={ +/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc13 */ { PFM_REG_CONFIG , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, + { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={ +/* pmd0 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd1 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd2 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd3 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd4 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +/* pmd8 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd9 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd10 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd11 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd12 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd13 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd14 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd15 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd16 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd17 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, + { PFM_REG_END , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static int +pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + int ret; + int is_loaded; + + /* sanitfy check */ + if (ctx == NULL) return -EINVAL; + + is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED; + + /* + * we must clear the (instruction) debug registers if pmc13.ta bit is cleared + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 13 && is_loaded && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) { + + DPRINT(("pmc[%d]=0x%lx has active pmc13.ta cleared, clearing ibr\n", cnum, *val)); + + /* don't mix debug with perfmon */ + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs); + if (ret) return ret; + } + + /* + * we must clear the (data) debug registers if pmc11.pt bit is cleared + * before they are written (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 11 && is_loaded && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) { + + DPRINT(("pmc[%d]=0x%lx has active pmc11.pt cleared, clearing dbr\n", cnum, *val)); + + /* don't mix debug with perfmon */ + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs); + if (ret) return ret; + } + return 0; +} + +/* + * impl_pmcs, impl_pmds are computed at runtime to minimize errors! + */ +static pmu_config_t pmu_conf_ita={ + .pmu_name = "Itanium", + .pmu_family = 0x7, + .ovfl_val = (1UL << 32) - 1, + .pmd_desc = pfm_ita_pmd_desc, + .pmc_desc = pfm_ita_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1, /* debug register are use for range retrictions */ +}; + + diff --git a/xen/arch/ia64/linux-xen/perfmon_mckinley.h b/xen/arch/ia64/linux-xen/perfmon_mckinley.h new file mode 100644 index 0000000000..9becccda28 --- /dev/null +++ b/xen/arch/ia64/linux-xen/perfmon_mckinley.h @@ -0,0 +1,187 @@ +/* + * This file contains the McKinley PMU register description tables + * and pmc checker used by perfmon.c. + * + * Copyright (C) 2002-2003 Hewlett Packard Co + * Stephane Eranian + */ +static int pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + +static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={ +/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc13 */ { PFM_REG_CONFIG , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc14 */ { PFM_REG_CONFIG , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, +/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}}, + { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={ +/* pmd0 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd1 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}}, +/* pmd2 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd3 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, +/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}}, +/* pmd8 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd9 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd10 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd11 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd12 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd13 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd14 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd15 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd16 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}}, +/* pmd17 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}}, + { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +/* + * PMC reserved fields must have their power-up values preserved + */ +static int +pfm_mck_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + unsigned long tmp1, tmp2, ival = *val; + + /* remove reserved areas from user value */ + tmp1 = ival & PMC_RSVD_MASK(cnum); + + /* get reserved fields values */ + tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum); + + *val = tmp1 | tmp2; + + DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", + cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); + return 0; +} + +/* + * task can be NULL if the context is unloaded + */ +static int +pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + int ret = 0, check_case1 = 0; + unsigned long val8 = 0, val14 = 0, val13 = 0; + int is_loaded; + + /* first preserve the reserved fields */ + pfm_mck_reserved(cnum, val, regs); + + /* sanitfy check */ + if (ctx == NULL) return -EINVAL; + + is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED; + + /* + * we must clear the debug registers if pmc13 has a value which enable + * memory pipeline event constraints. In this case we need to clear the + * the debug registers if they have not yet been accessed. This is required + * to avoid picking stale state. + * PMC13 is "active" if: + * one of the pmc13.cfg_dbrpXX field is different from 0x3 + * AND + * at the corresponding pmc13.ena_dbrpXX is set. + */ + DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, *val, ctx->ctx_fl_using_dbreg, is_loaded)); + + if (cnum == 13 && is_loaded + && (*val & 0x1e00000000000UL) && (*val & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) { + + DPRINT(("pmc[%d]=0x%lx has active pmc13 settings, clearing dbr\n", cnum, *val)); + + /* don't mix debug with perfmon */ + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs); + if (ret) return ret; + } + /* + * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled + * before they are (fl_using_dbreg==0) to avoid picking up stale information. + */ + if (cnum == 14 && is_loaded && ((*val & 0x2222UL) != 0x2222UL) && ctx->ctx_fl_using_dbreg == 0) { + + DPRINT(("pmc[%d]=0x%lx has active pmc14 settings, clearing ibr\n", cnum, *val)); + + /* don't mix debug with perfmon */ + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs); + if (ret) return ret; + + } + + switch(cnum) { + case 4: *val |= 1UL << 23; /* force power enable bit */ + break; + case 8: val8 = *val; + val13 = ctx->ctx_pmcs[13]; + val14 = ctx->ctx_pmcs[14]; + check_case1 = 1; + break; + case 13: val8 = ctx->ctx_pmcs[8]; + val13 = *val; + val14 = ctx->ctx_pmcs[14]; + check_case1 = 1; + break; + case 14: val8 = ctx->ctx_pmcs[8]; + val13 = ctx->ctx_pmcs[13]; + val14 = *val; + check_case1 = 1; + break; + } + /* check illegal configuration which can produce inconsistencies in tagging + * i-side events in L1D and L2 caches + */ + if (check_case1) { + ret = ((val13 >> 45) & 0xf) == 0 + && ((val8 & 0x1) == 0) + && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0) + ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0)); + + if (ret) DPRINT((KERN_DEBUG "perfmon: failure check_case1\n")); + } + + return ret ? -EINVAL : 0; +} + +/* + * impl_pmcs, impl_pmds are computed at runtime to minimize errors! + */ +static pmu_config_t pmu_conf_mck={ + .pmu_name = "Itanium 2", + .pmu_family = 0x1f, + .flags = PFM_PMU_IRQ_RESEND, + .ovfl_val = (1UL << 47) - 1, + .pmd_desc = pfm_mck_pmd_desc, + .pmc_desc = pfm_mck_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1 /* debug register are use for range retrictions */ +}; + + diff --git a/xen/arch/ia64/linux-xen/perfmon_montecito.h b/xen/arch/ia64/linux-xen/perfmon_montecito.h new file mode 100644 index 0000000000..cd06ac6a68 --- /dev/null +++ b/xen/arch/ia64/linux-xen/perfmon_montecito.h @@ -0,0 +1,269 @@ +/* + * This file contains the Montecito PMU register description tables + * and pmc checker used by perfmon.c. + * + * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P. + * Contributed by Stephane Eranian + */ +static int pfm_mont_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); + +#define RDEP_MONT_ETB (RDEP(38)|RDEP(39)|RDEP(48)|RDEP(49)|RDEP(50)|RDEP(51)|RDEP(52)|RDEP(53)|RDEP(54)|\ + RDEP(55)|RDEP(56)|RDEP(57)|RDEP(58)|RDEP(59)|RDEP(60)|RDEP(61)|RDEP(62)|RDEP(63)) +#define RDEP_MONT_DEAR (RDEP(32)|RDEP(33)|RDEP(36)) +#define RDEP_MONT_IEAR (RDEP(34)|RDEP(35)) + +static pfm_reg_desc_t pfm_mont_pmc_desc[PMU_MAX_PMCS]={ +/* pmc0 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc4 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(4),0, 0, 0}, {0,0, 0, 0}}, +/* pmc5 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(5),0, 0, 0}, {0,0, 0, 0}}, +/* pmc6 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(6),0, 0, 0}, {0,0, 0, 0}}, +/* pmc7 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(7),0, 0, 0}, {0,0, 0, 0}}, +/* pmc8 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(8),0, 0, 0}, {0,0, 0, 0}}, +/* pmc9 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(9),0, 0, 0}, {0,0, 0, 0}}, +/* pmc10 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(10),0, 0, 0}, {0,0, 0, 0}}, +/* pmc11 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(11),0, 0, 0}, {0,0, 0, 0}}, +/* pmc12 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(12),0, 0, 0}, {0,0, 0, 0}}, +/* pmc13 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(13),0, 0, 0}, {0,0, 0, 0}}, +/* pmc14 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(14),0, 0, 0}, {0,0, 0, 0}}, +/* pmc15 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(15),0, 0, 0}, {0,0, 0, 0}}, +/* pmc16 */ { PFM_REG_NOTIMPL, }, +/* pmc17 */ { PFM_REG_NOTIMPL, }, +/* pmc18 */ { PFM_REG_NOTIMPL, }, +/* pmc19 */ { PFM_REG_NOTIMPL, }, +/* pmc20 */ { PFM_REG_NOTIMPL, }, +/* pmc21 */ { PFM_REG_NOTIMPL, }, +/* pmc22 */ { PFM_REG_NOTIMPL, }, +/* pmc23 */ { PFM_REG_NOTIMPL, }, +/* pmc24 */ { PFM_REG_NOTIMPL, }, +/* pmc25 */ { PFM_REG_NOTIMPL, }, +/* pmc26 */ { PFM_REG_NOTIMPL, }, +/* pmc27 */ { PFM_REG_NOTIMPL, }, +/* pmc28 */ { PFM_REG_NOTIMPL, }, +/* pmc29 */ { PFM_REG_NOTIMPL, }, +/* pmc30 */ { PFM_REG_NOTIMPL, }, +/* pmc31 */ { PFM_REG_NOTIMPL, }, +/* pmc32 */ { PFM_REG_CONFIG, 0, 0x30f01ffffffffff, 0x30f01ffffffffff, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc33 */ { PFM_REG_CONFIG, 0, 0x0, 0x1ffffffffff, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc34 */ { PFM_REG_CONFIG, 0, 0xf01ffffffffff, 0xf01ffffffffff, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc35 */ { PFM_REG_CONFIG, 0, 0x0, 0x1ffffffffff, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc36 */ { PFM_REG_CONFIG, 0, 0xfffffff0, 0xf, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc37 */ { PFM_REG_MONITOR, 4, 0x0, 0x3fff, NULL, pfm_mont_pmc_check, {RDEP_MONT_IEAR, 0, 0, 0}, {0, 0, 0, 0}}, +/* pmc38 */ { PFM_REG_CONFIG, 0, 0xdb6, 0x2492, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc39 */ { PFM_REG_MONITOR, 6, 0x0, 0xffcf, NULL, pfm_mont_pmc_check, {RDEP_MONT_ETB,0, 0, 0}, {0,0, 0, 0}}, +/* pmc40 */ { PFM_REG_MONITOR, 6, 0x2000000, 0xf01cf, NULL, pfm_mont_pmc_check, {RDEP_MONT_DEAR,0, 0, 0}, {0,0, 0, 0}}, +/* pmc41 */ { PFM_REG_CONFIG, 0, 0x00002078fefefefe, 0x1e00018181818, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}}, +/* pmc42 */ { PFM_REG_MONITOR, 6, 0x0, 0x7ff4f, NULL, pfm_mont_pmc_check, {RDEP_MONT_ETB,0, 0, 0}, {0,0, 0, 0}}, + { PFM_REG_END , 0, 0x0, -1, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +static pfm_reg_desc_t pfm_mont_pmd_desc[PMU_MAX_PMDS]={ +/* pmd0 */ { PFM_REG_NOTIMPL, }, +/* pmd1 */ { PFM_REG_NOTIMPL, }, +/* pmd2 */ { PFM_REG_NOTIMPL, }, +/* pmd3 */ { PFM_REG_NOTIMPL, }, +/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(4),0, 0, 0}}, +/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(5),0, 0, 0}}, +/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(6),0, 0, 0}}, +/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(7),0, 0, 0}}, +/* pmd8 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(8),0, 0, 0}}, +/* pmd9 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(9),0, 0, 0}}, +/* pmd10 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(10),0, 0, 0}}, +/* pmd11 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(11),0, 0, 0}}, +/* pmd12 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(12),0, 0, 0}}, +/* pmd13 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(13),0, 0, 0}}, +/* pmd14 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(14),0, 0, 0}}, +/* pmd15 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(15),0, 0, 0}}, +/* pmd16 */ { PFM_REG_NOTIMPL, }, +/* pmd17 */ { PFM_REG_NOTIMPL, }, +/* pmd18 */ { PFM_REG_NOTIMPL, }, +/* pmd19 */ { PFM_REG_NOTIMPL, }, +/* pmd20 */ { PFM_REG_NOTIMPL, }, +/* pmd21 */ { PFM_REG_NOTIMPL, }, +/* pmd22 */ { PFM_REG_NOTIMPL, }, +/* pmd23 */ { PFM_REG_NOTIMPL, }, +/* pmd24 */ { PFM_REG_NOTIMPL, }, +/* pmd25 */ { PFM_REG_NOTIMPL, }, +/* pmd26 */ { PFM_REG_NOTIMPL, }, +/* pmd27 */ { PFM_REG_NOTIMPL, }, +/* pmd28 */ { PFM_REG_NOTIMPL, }, +/* pmd29 */ { PFM_REG_NOTIMPL, }, +/* pmd30 */ { PFM_REG_NOTIMPL, }, +/* pmd31 */ { PFM_REG_NOTIMPL, }, +/* pmd32 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(33)|RDEP(36),0, 0, 0}, {RDEP(40),0, 0, 0}}, +/* pmd33 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(32)|RDEP(36),0, 0, 0}, {RDEP(40),0, 0, 0}}, +/* pmd34 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(35),0, 0, 0}, {RDEP(37),0, 0, 0}}, +/* pmd35 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(34),0, 0, 0}, {RDEP(37),0, 0, 0}}, +/* pmd36 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(32)|RDEP(33),0, 0, 0}, {RDEP(40),0, 0, 0}}, +/* pmd37 */ { PFM_REG_NOTIMPL, }, +/* pmd38 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd39 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd40 */ { PFM_REG_NOTIMPL, }, +/* pmd41 */ { PFM_REG_NOTIMPL, }, +/* pmd42 */ { PFM_REG_NOTIMPL, }, +/* pmd43 */ { PFM_REG_NOTIMPL, }, +/* pmd44 */ { PFM_REG_NOTIMPL, }, +/* pmd45 */ { PFM_REG_NOTIMPL, }, +/* pmd46 */ { PFM_REG_NOTIMPL, }, +/* pmd47 */ { PFM_REG_NOTIMPL, }, +/* pmd48 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd49 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd50 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd51 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd52 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd53 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd54 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd55 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd56 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd57 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd58 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd59 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd60 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd61 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd62 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, +/* pmd63 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}}, + { PFM_REG_END , 0, 0x0, -1, NULL, NULL, {0,}, {0,}}, /* end marker */ +}; + +/* + * PMC reserved fields must have their power-up values preserved + */ +static int +pfm_mont_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + unsigned long tmp1, tmp2, ival = *val; + + /* remove reserved areas from user value */ + tmp1 = ival & PMC_RSVD_MASK(cnum); + + /* get reserved fields values */ + tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum); + + *val = tmp1 | tmp2; + + DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n", + cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val)); + return 0; +} + +/* + * task can be NULL if the context is unloaded + */ +static int +pfm_mont_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs) +{ + int ret = 0; + unsigned long val32 = 0, val38 = 0, val41 = 0; + unsigned long tmpval; + int check_case1 = 0; + int is_loaded; + + /* first preserve the reserved fields */ + pfm_mont_reserved(cnum, val, regs); + + tmpval = *val; + + /* sanity check */ + if (ctx == NULL) return -EINVAL; + + is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED; + + /* + * we must clear the debug registers if pmc41 has a value which enable + * memory pipeline event constraints. In this case we need to clear the + * the debug registers if they have not yet been accessed. This is required + * to avoid picking stale state. + * PMC41 is "active" if: + * one of the pmc41.cfg_dtagXX field is different from 0x3 + * AND + * at the corresponding pmc41.en_dbrpXX is set. + * AND + * ctx_fl_using_dbreg == 0 (i.e., dbr not yet used) + */ + DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, tmpval, ctx->ctx_fl_using_dbreg, is_loaded)); + + if (cnum == 41 && is_loaded + && (tmpval & 0x1e00000000000) && (tmpval & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) { + + DPRINT(("pmc[%d]=0x%lx has active pmc41 settings, clearing dbr\n", cnum, tmpval)); + + /* don't mix debug with perfmon */ + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers if: + * AND + */ + ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs); + if (ret) return ret; + } + /* + * we must clear the (instruction) debug registers if: + * pmc38.ig_ibrpX is 0 (enabled) + * AND + * ctx_fl_using_dbreg == 0 (i.e., dbr not yet used) + */ + if (cnum == 38 && is_loaded && ((tmpval & 0x492UL) != 0x492UL) && ctx->ctx_fl_using_dbreg == 0) { + + DPRINT(("pmc38=0x%lx has active pmc38 settings, clearing ibr\n", tmpval)); + + /* don't mix debug with perfmon */ + if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL; + + /* + * a count of 0 will mark the debug registers as in use and also + * ensure that they are properly cleared. + */ + ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs); + if (ret) return ret; + + } + switch(cnum) { + case 32: val32 = *val; + val38 = ctx->ctx_pmcs[38]; + val41 = ctx->ctx_pmcs[41]; + check_case1 = 1; + break; + case 38: val38 = *val; + val32 = ctx->ctx_pmcs[32]; + val41 = ctx->ctx_pmcs[41]; + check_case1 = 1; + break; + case 41: val41 = *val; + val32 = ctx->ctx_pmcs[32]; + val38 = ctx->ctx_pmcs[38]; + check_case1 = 1; + break; + } + /* check illegal configuration which can produce inconsistencies in tagging + * i-side events in L1D and L2 caches + */ + if (check_case1) { + ret = (((val41 >> 45) & 0xf) == 0 && ((val32>>57) & 0x1) == 0) + && ((((val38>>1) & 0x3) == 0x2 || ((val38>>1) & 0x3) == 0) + || (((val38>>4) & 0x3) == 0x2 || ((val38>>4) & 0x3) == 0)); + if (ret) { + DPRINT(("invalid config pmc38=0x%lx pmc41=0x%lx pmc32=0x%lx\n", val38, val41, val32)); + return -EINVAL; + } + } + *val = tmpval; + return 0; +} + +/* + * impl_pmcs, impl_pmds are computed at runtime to minimize errors! + */ +static pmu_config_t pmu_conf_mont={ + .pmu_name = "Montecito", + .pmu_family = 0x20, + .flags = PFM_PMU_IRQ_RESEND, + .ovfl_val = (1UL << 47) - 1, + .pmd_desc = pfm_mont_pmd_desc, + .pmc_desc = pfm_mont_pmc_desc, + .num_ibrs = 8, + .num_dbrs = 8, + .use_rr_dbregs = 1 /* debug register are use for range retrictions */ +}; diff --git a/xen/arch/ia64/linux/README.origin b/xen/arch/ia64/linux/README.origin index 66ef299d7d..87da72ac8f 100644 --- a/xen/arch/ia64/linux/README.origin +++ b/xen/arch/ia64/linux/README.origin @@ -24,3 +24,6 @@ idiv64.S -> linux/arch/ia64/lib/idiv64.S memcpy_mck.S -> linux/arch/ia64/lib/memcpy_mck.S memset.S -> linux/arch/ia64/lib/memset.S strlen.S -> linux/arch/ia64/lib/strlen.S + +# The files below are from Linux-2.6.16.33 +carta_random.S -> linux/arch/ia64/lib/carta_random.S diff --git a/xen/arch/ia64/linux/carta_random.S b/xen/arch/ia64/linux/carta_random.S new file mode 100644 index 0000000000..d0674c3603 --- /dev/null +++ b/xen/arch/ia64/linux/carta_random.S @@ -0,0 +1,54 @@ +/* + * Fast, simple, yet decent quality random number generator based on + * a paper by David G. Carta ("Two Fast Implementations of the + * `Minimal Standard' Random Number Generator," Communications of the + * ACM, January, 1990). + * + * Copyright (C) 2002 Hewlett-Packard Co + * David Mosberger-Tang + */ + +#include + +#define a r2 +#define m r3 +#define lo r8 +#define hi r9 +#define t0 r16 +#define t1 r17 +#define seed r32 + +GLOBAL_ENTRY(carta_random32) + movl a = (16807 << 16) | 16807 + ;; + pmpyshr2.u t0 = a, seed, 0 + pmpyshr2.u t1 = a, seed, 16 + ;; + unpack2.l t0 = t1, t0 + dep m = -1, r0, 0, 31 + ;; + zxt4 lo = t0 + shr.u hi = t0, 32 + ;; + dep t0 = 0, hi, 15, 49 // t0 = (hi & 0x7fff) + ;; + shl t0 = t0, 16 // t0 = (hi & 0x7fff) << 16 + shr t1 = hi, 15 // t1 = (hi >> 15) + ;; + add lo = lo, t0 + ;; + cmp.gtu p6, p0 = lo, m + ;; +(p6) and lo = lo, m + ;; +(p6) add lo = 1, lo + ;; + add lo = lo, t1 + ;; + cmp.gtu p6, p0 = lo, m + ;; +(p6) and lo = lo, m + ;; +(p6) add lo = 1, lo + br.ret.sptk.many rp +END(carta_random32) diff --git a/xen/include/asm-ia64/linux-xen/asm/README.origin b/xen/include/asm-ia64/linux-xen/asm/README.origin index 3f2a03f704..f8d8375770 100644 --- a/xen/include/asm-ia64/linux-xen/asm/README.origin +++ b/xen/include/asm-ia64/linux-xen/asm/README.origin @@ -30,3 +30,7 @@ types.h -> linux/include/asm-ia64/types.h # The files below are from Linux-2.6.16 iosapic.h -> linux/include/asm-ia64/iosapic.h + +# The files below are from Linux-2.6.16.33 +perfmon.h -> linux/include/asm-ia64/perfmon.h +perfmon_default_smpl.h -> linux/include/asm-ia64/perfmon_default_smpl.h diff --git a/xen/include/asm-ia64/linux-xen/asm/perfmon.h b/xen/include/asm-ia64/linux-xen/asm/perfmon.h new file mode 100644 index 0000000000..7f3333dd00 --- /dev/null +++ b/xen/include/asm-ia64/linux-xen/asm/perfmon.h @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2001-2003 Hewlett-Packard Co + * Stephane Eranian + */ + +#ifndef _ASM_IA64_PERFMON_H +#define _ASM_IA64_PERFMON_H + +/* + * perfmon comamnds supported on all CPU models + */ +#define PFM_WRITE_PMCS 0x01 +#define PFM_WRITE_PMDS 0x02 +#define PFM_READ_PMDS 0x03 +#define PFM_STOP 0x04 +#define PFM_START 0x05 +#define PFM_ENABLE 0x06 /* obsolete */ +#define PFM_DISABLE 0x07 /* obsolete */ +#define PFM_CREATE_CONTEXT 0x08 +#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */ +#define PFM_RESTART 0x0a +#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */ +#define PFM_GET_FEATURES 0x0c +#define PFM_DEBUG 0x0d +#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */ +#define PFM_GET_PMC_RESET_VAL 0x0f +#define PFM_LOAD_CONTEXT 0x10 +#define PFM_UNLOAD_CONTEXT 0x11 + +/* + * PMU model specific commands (may not be supported on all PMU models) + */ +#define PFM_WRITE_IBRS 0x20 +#define PFM_WRITE_DBRS 0x21 + +/* + * context flags + */ +#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */ +#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */ +#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */ + +/* + * event set flags + */ +#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */ + +/* + * PMC flags + */ +#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */ +#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */ + +/* + * PMD/PMC/IBR/DBR return flags (ignored on input) + * + * Those flags are used on output and must be checked in case EAGAIN is returned + * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure. + */ +#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */ +#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */ +#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL) + +#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0) + +typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */ + +/* + * Request structure used to define a context + */ +typedef struct { + pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */ + unsigned long ctx_flags; /* noblock/block */ + unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */ + unsigned short ctx_reserved1; /* for future use */ + int ctx_fd; /* return arg: unique identification for context */ + void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */ + unsigned long ctx_reserved2[11];/* for future use */ +} pfarg_context_t; + +/* + * Request structure used to write/read a PMC or PMD + */ +typedef struct { + unsigned int reg_num; /* which register */ + unsigned short reg_set; /* event set for this register */ + unsigned short reg_reserved1; /* for future use */ + + unsigned long reg_value; /* initial pmc/pmd value */ + unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */ + + unsigned long reg_long_reset; /* reset after buffer overflow notification */ + unsigned long reg_short_reset; /* reset after counter overflow */ + + unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */ + unsigned long reg_random_seed; /* seed value when randomization is used */ + unsigned long reg_random_mask; /* bitmask used to limit random value */ + unsigned long reg_last_reset_val;/* return: PMD last reset value */ + + unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */ + unsigned long reg_smpl_eventid; /* opaque sampling event identifier */ + + unsigned long reg_reserved2[3]; /* for future use */ +} pfarg_reg_t; + +typedef struct { + unsigned int dbreg_num; /* which debug register */ + unsigned short dbreg_set; /* event set for this register */ + unsigned short dbreg_reserved1; /* for future use */ + unsigned long dbreg_value; /* value for debug register */ + unsigned long dbreg_flags; /* return: dbreg error */ + unsigned long dbreg_reserved2[1]; /* for future use */ +} pfarg_dbreg_t; + +typedef struct { + unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */ + unsigned int ft_reserved; /* reserved for future use */ + unsigned long reserved[4]; /* for future use */ +} pfarg_features_t; + +typedef struct { + pid_t load_pid; /* process to load the context into */ + unsigned short load_set; /* first event set to load */ + unsigned short load_reserved1; /* for future use */ + unsigned long load_reserved2[3]; /* for future use */ +} pfarg_load_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */ + unsigned short msg_active_set; /* active set at the time of overflow */ + unsigned short msg_reserved1; /* for future use */ + unsigned int msg_reserved2; /* for future use */ + unsigned long msg_tstamp; /* for perf tuning/debug */ +} pfm_ovfl_msg_t; + +typedef struct { + int msg_type; /* generic message header */ + int msg_ctx_fd; /* generic message header */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_end_msg_t; + +typedef struct { + int msg_type; /* type of the message */ + int msg_ctx_fd; /* unique identifier for the context */ + unsigned long msg_tstamp; /* for perf tuning */ +} pfm_gen_msg_t; + +#define PFM_MSG_OVFL 1 /* an overflow happened */ +#define PFM_MSG_END 2 /* task to which context was attached ended */ + +typedef union { + pfm_ovfl_msg_t pfm_ovfl_msg; + pfm_end_msg_t pfm_end_msg; + pfm_gen_msg_t pfm_gen_msg; +} pfm_msg_t; + +/* + * Define the version numbers for both perfmon as a whole and the sampling buffer format. + */ +#define PFM_VERSION_MAJ 2U +#define PFM_VERSION_MIN 0U +#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff)) +#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff) +#define PFM_VERSION_MINOR(x) ((x) & 0xffff) + + +/* + * miscellaneous architected definitions + */ +#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */ +#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */ +#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */ + +#ifdef __KERNEL__ + +extern long perfmonctl(int fd, int cmd, void *arg, int narg); + +typedef struct { + void (*handler)(int irq, void *arg, struct pt_regs *regs); +} pfm_intr_handler_desc_t; + +extern void pfm_save_regs (struct task_struct *); +extern void pfm_load_regs (struct task_struct *); + +extern void pfm_exit_thread(struct task_struct *); +extern int pfm_use_debug_registers(struct task_struct *); +extern int pfm_release_debug_registers(struct task_struct *); +extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin); +extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs); +extern void pfm_init_percpu(void); +extern void pfm_handle_work(void); +extern int pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *h); +extern int pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *h); + + + +/* + * Reset PMD register flags + */ +#define PFM_PMD_SHORT_RESET 0 +#define PFM_PMD_LONG_RESET 1 + +typedef union { + unsigned int val; + struct { + unsigned int notify_user:1; /* notify user program of overflow */ + unsigned int reset_ovfl_pmds:1; /* reset overflowed PMDs */ + unsigned int block_task:1; /* block monitored task on kernel exit */ + unsigned int mask_monitoring:1; /* mask monitors via PMCx.plm */ + unsigned int reserved:28; /* for future use */ + } bits; +} pfm_ovfl_ctrl_t; + +typedef struct { + unsigned char ovfl_pmd; /* index of overflowed PMD */ + unsigned char ovfl_notify; /* =1 if monitor requested overflow notification */ + unsigned short active_set; /* event set active at the time of the overflow */ + pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */ + + unsigned long pmd_last_reset; /* last reset value of of the PMD */ + unsigned long smpl_pmds[4]; /* bitmask of other PMD of interest on overflow */ + unsigned long smpl_pmds_values[PMU_MAX_PMDS]; /* values for the other PMDs of interest */ + unsigned long pmd_value; /* current 64-bit value of the PMD */ + unsigned long pmd_eventid; /* eventid associated with PMD */ +} pfm_ovfl_arg_t; + + +typedef struct { + char *fmt_name; + pfm_uuid_t fmt_uuid; + size_t fmt_arg_size; + unsigned long fmt_flags; + + int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg); + int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size); + int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg); + int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp); + int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); + int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs); + int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs); + + struct list_head fmt_list; +} pfm_buffer_fmt_t; + +extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt); +extern int pfm_unregister_buffer_fmt(pfm_uuid_t uuid); + +/* + * perfmon interface exported to modules + */ +extern int pfm_mod_read_pmds(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs); +extern int pfm_mod_write_pmcs(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs); +extern int pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs); +extern int pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs); + +/* + * describe the content of the local_cpu_date->pfm_syst_info field + */ +#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exists */ +#define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */ +#define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */ + +/* + * sysctl control structure. visible to sampling formats + */ +typedef struct { + int debug; /* turn on/off debugging via syslog */ + int debug_ovfl; /* turn on/off debug printk in overflow handler */ + int fastctxsw; /* turn on/off fast (unsecure) ctxsw */ + int expert_mode; /* turn on/off value checking */ +} pfm_sysctl_t; +extern pfm_sysctl_t pfm_sysctl; + + +#endif /* __KERNEL__ */ + +#endif /* _ASM_IA64_PERFMON_H */ diff --git a/xen/include/asm-ia64/linux-xen/asm/perfmon_default_smpl.h b/xen/include/asm-ia64/linux-xen/asm/perfmon_default_smpl.h new file mode 100644 index 0000000000..48822c0811 --- /dev/null +++ b/xen/include/asm-ia64/linux-xen/asm/perfmon_default_smpl.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2002-2003 Hewlett-Packard Co + * Stephane Eranian + * + * This file implements the default sampling buffer format + * for Linux/ia64 perfmon subsystem. + */ +#ifndef __PERFMON_DEFAULT_SMPL_H__ +#define __PERFMON_DEFAULT_SMPL_H__ 1 + +#define PFM_DEFAULT_SMPL_UUID { \ + 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82, 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97} + +/* + * format specific parameters (passed at context creation) + */ +typedef struct { + unsigned long buf_size; /* size of the buffer in bytes */ + unsigned int flags; /* buffer specific flags */ + unsigned int res1; /* for future use */ + unsigned long reserved[2]; /* for future use */ +} pfm_default_smpl_arg_t; + +/* + * combined context+format specific structure. Can be passed + * to PFM_CONTEXT_CREATE + */ +typedef struct { + pfarg_context_t ctx_arg; + pfm_default_smpl_arg_t buf_arg; +} pfm_default_smpl_ctx_arg_t; + +/* + * This header is at the beginning of the sampling buffer returned to the user. + * It is directly followed by the first record. + */ +typedef struct { + unsigned long hdr_count; /* how many valid entries */ + unsigned long hdr_cur_offs; /* current offset from top of buffer */ + unsigned long hdr_reserved2; /* reserved for future use */ + + unsigned long hdr_overflows; /* how many times the buffer overflowed */ + unsigned long hdr_buf_size; /* how many bytes in the buffer */ + + unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */ + unsigned int hdr_reserved1; /* for future use */ + unsigned long hdr_reserved[10]; /* for future use */ +} pfm_default_smpl_hdr_t; + +/* + * Entry header in the sampling buffer. The header is directly followed + * with the values of the PMD registers of interest saved in increasing + * index order: PMD4, PMD5, and so on. How many PMDs are present depends + * on how the session was programmed. + * + * In the case where multiple counters overflow at the same time, multiple + * entries are written consecutively. + * + * last_reset_value member indicates the initial value of the overflowed PMD. + */ +typedef struct { + int pid; /* thread id (for NPTL, this is gettid()) */ + unsigned char reserved1[3]; /* reserved for future use */ + unsigned char ovfl_pmd; /* index of overflowed PMD */ + + unsigned long last_reset_val; /* initial value of overflowed PMD */ + unsigned long ip; /* where did the overflow interrupt happened */ + unsigned long tstamp; /* ar.itc when entering perfmon intr. handler */ + + unsigned short cpu; /* cpu on which the overfow occured */ + unsigned short set; /* event set active when overflow ocurred */ + int tgid; /* thread group id (for NPTL, this is getpid()) */ +} pfm_default_smpl_entry_t; + +#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */ +#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(pfm_default_smpl_entry_t)+(sizeof(unsigned long)*PFM_DEFAULT_MAX_PMDS)) +#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(pfm_default_smpl_hdr_t)+PFM_DEFAULT_MAX_ENTRY_SIZE) + +#define PFM_DEFAULT_SMPL_VERSION_MAJ 2U +#define PFM_DEFAULT_SMPL_VERSION_MIN 0U +#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff)) + +#endif /* __PERFMON_DEFAULT_SMPL_H__ */ diff --git a/xen/include/asm-ia64/linux-xen/linux/README.origin b/xen/include/asm-ia64/linux-xen/linux/README.origin index b84b7b65f1..6cc513be16 100644 --- a/xen/include/asm-ia64/linux-xen/linux/README.origin +++ b/xen/include/asm-ia64/linux-xen/linux/README.origin @@ -9,3 +9,6 @@ efi.h -> linux/include/linux/efi.h gfp.h -> linux/include/linux/gfp.h hardirq.h -> linux/include/linux/hardirq.h interrupt.h -> linux/include/linux/interrupt.h + +# The files below are from Linux-2.6.16.33 +oprofile.h -> linux/include/linux/oprofile.h diff --git a/xen/include/asm-ia64/linux-xen/linux/oprofile.h b/xen/include/asm-ia64/linux-xen/linux/oprofile.h new file mode 100644 index 0000000000..559c4c38a9 --- /dev/null +++ b/xen/include/asm-ia64/linux-xen/linux/oprofile.h @@ -0,0 +1,119 @@ +/** + * @file oprofile.h + * + * API for machine-specific interrupts to interface + * to oprofile. + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#ifndef OPROFILE_H +#define OPROFILE_H + +#include +#include +#include + +struct super_block; +struct dentry; +struct file_operations; +struct pt_regs; + +/* Operations structure to be filled in */ +struct oprofile_operations { + /* create any necessary configuration files in the oprofile fs. + * Optional. */ + int (*create_files)(struct super_block * sb, struct dentry * root); + /* Do any necessary interrupt setup. Optional. */ + int (*setup)(void); + /* Do any necessary interrupt shutdown. Optional. */ + void (*shutdown)(void); + /* Start delivering interrupts. */ + int (*start)(void); + /* Stop delivering interrupts. */ + void (*stop)(void); + /* Initiate a stack backtrace. Optional. */ + void (*backtrace)(struct pt_regs * const regs, unsigned int depth); + /* CPU identification string. */ + char * cpu_type; +}; + +/** + * One-time initialisation. *ops must be set to a filled-in + * operations structure. This is called even in timer interrupt + * mode so an arch can set a backtrace callback. + * + * If an error occurs, the fields should be left untouched. + */ +int oprofile_arch_init(struct oprofile_operations * ops); + +/** + * One-time exit/cleanup for the arch. + */ +void oprofile_arch_exit(void); + +/** + * Add a sample. This may be called from any context. Pass + * smp_processor_id() as cpu. + */ +void oprofile_add_sample(struct pt_regs * const regs, unsigned long event); + +/* Use this instead when the PC value is not from the regs. Doesn't + * backtrace. */ +void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event); + +/* add a backtrace entry, to be called from the ->backtrace callback */ +void oprofile_add_trace(unsigned long eip); + + +/** + * Create a file of the given name as a child of the given root, with + * the specified file operations. + */ +int oprofilefs_create_file(struct super_block * sb, struct dentry * root, + char const * name, struct file_operations * fops); + +int oprofilefs_create_file_perm(struct super_block * sb, struct dentry * root, + char const * name, struct file_operations * fops, int perm); + +/** Create a file for read/write access to an unsigned long. */ +int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root, + char const * name, ulong * val); + +/** Create a file for read-only access to an unsigned long. */ +int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root, + char const * name, ulong * val); + +/** Create a file for read-only access to an atomic_t. */ +int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root, + char const * name, atomic_t * val); + +/** create a directory */ +struct dentry * oprofilefs_mkdir(struct super_block * sb, struct dentry * root, + char const * name); + +/** + * Write the given asciz string to the given user buffer @buf, updating *offset + * appropriately. Returns bytes written or -EFAULT. + */ +ssize_t oprofilefs_str_to_user(char const * str, char __user * buf, size_t count, loff_t * offset); + +/** + * Convert an unsigned long value into ASCII and copy it to the user buffer @buf, + * updating *offset appropriately. Returns bytes written or -EFAULT. + */ +ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user * buf, size_t count, loff_t * offset); + +/** + * Read an ASCII string for a number from a userspace buffer and fill *val on success. + * Returns 0 on success, < 0 on error. + */ +int oprofilefs_ulong_from_user(unsigned long * val, char const __user * buf, size_t count); + +/** lock for read/write safety */ +extern spinlock_t oprofilefs_lock; + +#endif /* OPROFILE_H */ From 0ef613d426ada2e0951e7976df76c75c4355ac2b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 11:19:40 -0700 Subject: [PATCH 042/282] [IA64] import perfmon, oprofile related files from linux to linux-sparse Signed-off-by: Isaku Yamahata Updated to 2.6.16.33 Signed-off-by: Alex Williamson --- .../arch/ia64/kernel/perfmon.c | 6852 +++++++++++++++++ .../arch/ia64/oprofile/Makefile | 10 + .../arch/ia64/oprofile/init.c | 38 + .../arch/ia64/oprofile/perfmon.c | 100 + 4 files changed, 7000 insertions(+) create mode 100644 linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c create mode 100644 linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile create mode 100644 linux-2.6-xen-sparse/arch/ia64/oprofile/init.c create mode 100644 linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c b/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c new file mode 100644 index 0000000000..9b42b02b85 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c @@ -0,0 +1,6852 @@ +/* + * This file implements the perfmon-2 subsystem which is used + * to program the IA-64 Performance Monitoring Unit (PMU). + * + * The initial version of perfmon.c was written by + * Ganesh Venkitachalam, IBM Corp. + * + * Then it was modified for perfmon-1.x by Stephane Eranian and + * David Mosberger, Hewlett Packard Co. + * + * Version Perfmon-2.x is a rewrite of perfmon-1.x + * by Stephane Eranian, Hewlett Packard Co. + * + * Copyright (C) 1999-2005 Hewlett Packard Co + * Stephane Eranian + * David Mosberger-Tang + * + * More information about perfmon available at: + * http://www.hpl.hp.com/research/linux/perfmon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PERFMON +/* + * perfmon context state + */ +#define PFM_CTX_UNLOADED 1 /* context is not loaded onto any task */ +#define PFM_CTX_LOADED 2 /* context is loaded onto a task */ +#define PFM_CTX_MASKED 3 /* context is loaded but monitoring is masked due to overflow */ +#define PFM_CTX_ZOMBIE 4 /* owner of the context is closing it */ + +#define PFM_INVALID_ACTIVATION (~0UL) + +/* + * depth of message queue + */ +#define PFM_MAX_MSGS 32 +#define PFM_CTXQ_EMPTY(g) ((g)->ctx_msgq_head == (g)->ctx_msgq_tail) + +/* + * type of a PMU register (bitmask). + * bitmask structure: + * bit0 : register implemented + * bit1 : end marker + * bit2-3 : reserved + * bit4 : pmc has pmc.pm + * bit5 : pmc controls a counter (has pmc.oi), pmd is used as counter + * bit6-7 : register type + * bit8-31: reserved + */ +#define PFM_REG_NOTIMPL 0x0 /* not implemented at all */ +#define PFM_REG_IMPL 0x1 /* register implemented */ +#define PFM_REG_END 0x2 /* end marker */ +#define PFM_REG_MONITOR (0x1<<4|PFM_REG_IMPL) /* a PMC with a pmc.pm field only */ +#define PFM_REG_COUNTING (0x2<<4|PFM_REG_MONITOR) /* a monitor + pmc.oi+ PMD used as a counter */ +#define PFM_REG_CONTROL (0x4<<4|PFM_REG_IMPL) /* PMU control register */ +#define PFM_REG_CONFIG (0x8<<4|PFM_REG_IMPL) /* configuration register */ +#define PFM_REG_BUFFER (0xc<<4|PFM_REG_IMPL) /* PMD used as buffer */ + +#define PMC_IS_LAST(i) (pmu_conf->pmc_desc[i].type & PFM_REG_END) +#define PMD_IS_LAST(i) (pmu_conf->pmd_desc[i].type & PFM_REG_END) + +#define PMC_OVFL_NOTIFY(ctx, i) ((ctx)->ctx_pmds[i].flags & PFM_REGFL_OVFL_NOTIFY) + +/* i assumed unsigned */ +#define PMC_IS_IMPL(i) (i< PMU_MAX_PMCS && (pmu_conf->pmc_desc[i].type & PFM_REG_IMPL)) +#define PMD_IS_IMPL(i) (i< PMU_MAX_PMDS && (pmu_conf->pmd_desc[i].type & PFM_REG_IMPL)) + +/* XXX: these assume that register i is implemented */ +#define PMD_IS_COUNTING(i) ((pmu_conf->pmd_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_COUNTING(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_COUNTING) == PFM_REG_COUNTING) +#define PMC_IS_MONITOR(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_MONITOR) == PFM_REG_MONITOR) +#define PMC_IS_CONTROL(i) ((pmu_conf->pmc_desc[i].type & PFM_REG_CONTROL) == PFM_REG_CONTROL) + +#define PMC_DFL_VAL(i) pmu_conf->pmc_desc[i].default_value +#define PMC_RSVD_MASK(i) pmu_conf->pmc_desc[i].reserved_mask +#define PMD_PMD_DEP(i) pmu_conf->pmd_desc[i].dep_pmd[0] +#define PMC_PMD_DEP(i) pmu_conf->pmc_desc[i].dep_pmd[0] + +#define PFM_NUM_IBRS IA64_NUM_DBG_REGS +#define PFM_NUM_DBRS IA64_NUM_DBG_REGS + +#define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) +#define CTX_HAS_SMPL(c) ((c)->ctx_fl_is_sampling) +#define PFM_CTX_TASK(h) (h)->ctx_task + +#define PMU_PMC_OI 5 /* position of pmc.oi bit */ + +/* XXX: does not support more than 64 PMDs */ +#define CTX_USED_PMD(ctx, mask) (ctx)->ctx_used_pmds[0] |= (mask) +#define CTX_IS_USED_PMD(ctx, c) (((ctx)->ctx_used_pmds[0] & (1UL << (c))) != 0UL) + +#define CTX_USED_MONITOR(ctx, mask) (ctx)->ctx_used_monitors[0] |= (mask) + +#define CTX_USED_IBR(ctx,n) (ctx)->ctx_used_ibrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USED_DBR(ctx,n) (ctx)->ctx_used_dbrs[(n)>>6] |= 1UL<< ((n) % 64) +#define CTX_USES_DBREGS(ctx) (((pfm_context_t *)(ctx))->ctx_fl_using_dbreg==1) +#define PFM_CODE_RR 0 /* requesting code range restriction */ +#define PFM_DATA_RR 1 /* requestion data range restriction */ + +#define PFM_CPUINFO_CLEAR(v) pfm_get_cpu_var(pfm_syst_info) &= ~(v) +#define PFM_CPUINFO_SET(v) pfm_get_cpu_var(pfm_syst_info) |= (v) +#define PFM_CPUINFO_GET() pfm_get_cpu_var(pfm_syst_info) + +#define RDEP(x) (1UL<<(x)) + +/* + * context protection macros + * in SMP: + * - we need to protect against CPU concurrency (spin_lock) + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * in UP: + * - we need to protect against PMU overflow interrupts (local_irq_disable) + * + * spin_lock_irqsave()/spin_lock_irqrestore(): + * in SMP: local_irq_disable + spin_lock + * in UP : local_irq_disable + * + * spin_lock()/spin_lock(): + * in UP : removed automatically + * in SMP: protect against context accesses from other CPU. interrupts + * are not masked. This is useful for the PMU interrupt handler + * because we know we will not get PMU concurrency in that code. + */ +#define PROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_save ctx %p by [%d]\n", c, current->pid)); \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + DPRINT(("spinlocked ctx %p by [%d]\n", c, current->pid)); \ + } while(0) + +#define UNPROTECT_CTX(c, f) \ + do { \ + DPRINT(("spinlock_irq_restore ctx %p by [%d]\n", c, current->pid)); \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + +#define PROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_lock_irqsave(&(c)->ctx_lock, f); \ + } while(0) + + +#define UNPROTECT_CTX_NOPRINT(c, f) \ + do { \ + spin_unlock_irqrestore(&(c)->ctx_lock, f); \ + } while(0) + + +#define PROTECT_CTX_NOIRQ(c) \ + do { \ + spin_lock(&(c)->ctx_lock); \ + } while(0) + +#define UNPROTECT_CTX_NOIRQ(c) \ + do { \ + spin_unlock(&(c)->ctx_lock); \ + } while(0) + + +#ifdef CONFIG_SMP + +#define GET_ACTIVATION() pfm_get_cpu_var(pmu_activation_number) +#define INC_ACTIVATION() pfm_get_cpu_var(pmu_activation_number)++ +#define SET_ACTIVATION(c) (c)->ctx_last_activation = GET_ACTIVATION() + +#else /* !CONFIG_SMP */ +#define SET_ACTIVATION(t) do {} while(0) +#define GET_ACTIVATION(t) do {} while(0) +#define INC_ACTIVATION(t) do {} while(0) +#endif /* CONFIG_SMP */ + +#define SET_PMU_OWNER(t, c) do { pfm_get_cpu_var(pmu_owner) = (t); pfm_get_cpu_var(pmu_ctx) = (c); } while(0) +#define GET_PMU_OWNER() pfm_get_cpu_var(pmu_owner) +#define GET_PMU_CTX() pfm_get_cpu_var(pmu_ctx) + +#define LOCK_PFS(g) spin_lock_irqsave(&pfm_sessions.pfs_lock, g) +#define UNLOCK_PFS(g) spin_unlock_irqrestore(&pfm_sessions.pfs_lock, g) + +#define PFM_REG_RETFLAG_SET(flags, val) do { flags &= ~PFM_REG_RETFL_MASK; flags |= (val); } while(0) + +/* + * cmp0 must be the value of pmc0 + */ +#define PMC0_HAS_OVFL(cmp0) (cmp0 & ~0x1UL) + +#define PFMFS_MAGIC 0xa0b4d889 + +/* + * debugging + */ +#define PFM_DEBUGGING 1 +#ifdef PFM_DEBUGGING +#define DPRINT(a) \ + do { \ + if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ + } while (0) + +#define DPRINT_ovfl(a) \ + do { \ + if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d [%d] ", __FUNCTION__, __LINE__, smp_processor_id(), current->pid); printk a; } \ + } while (0) +#endif + +/* + * 64-bit software counter structure + * + * the next_reset_type is applied to the next call to pfm_reset_regs() + */ +typedef struct { + unsigned long val; /* virtual 64bit counter value */ + unsigned long lval; /* last reset value */ + unsigned long long_reset; /* reset value on sampling overflow */ + unsigned long short_reset; /* reset value on overflow */ + unsigned long reset_pmds[4]; /* which other pmds to reset when this counter overflows */ + unsigned long smpl_pmds[4]; /* which pmds are accessed when counter overflow */ + unsigned long seed; /* seed for random-number generator */ + unsigned long mask; /* mask for random-number generator */ + unsigned int flags; /* notify/do not notify */ + unsigned long eventid; /* overflow event identifier */ +} pfm_counter_t; + +/* + * context flags + */ +typedef struct { + unsigned int block:1; /* when 1, task will blocked on user notifications */ + unsigned int system:1; /* do system wide monitoring */ + unsigned int using_dbreg:1; /* using range restrictions (debug registers) */ + unsigned int is_sampling:1; /* true if using a custom format */ + unsigned int excl_idle:1; /* exclude idle task in system wide session */ + unsigned int going_zombie:1; /* context is zombie (MASKED+blocking) */ + unsigned int trap_reason:2; /* reason for going into pfm_handle_work() */ + unsigned int no_msg:1; /* no message sent on overflow */ + unsigned int can_restart:1; /* allowed to issue a PFM_RESTART */ + unsigned int reserved:22; +} pfm_context_flags_t; + +#define PFM_TRAP_REASON_NONE 0x0 /* default value */ +#define PFM_TRAP_REASON_BLOCK 0x1 /* we need to block on overflow */ +#define PFM_TRAP_REASON_RESET 0x2 /* we need to reset PMDs */ + + +/* + * perfmon context: encapsulates all the state of a monitoring session + */ + +typedef struct pfm_context { + spinlock_t ctx_lock; /* context protection */ + + pfm_context_flags_t ctx_flags; /* bitmask of flags (block reason incl.) */ + unsigned int ctx_state; /* state: active/inactive (no bitfield) */ + + struct task_struct *ctx_task; /* task to which context is attached */ + + unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ + + struct completion ctx_restart_done; /* use for blocking notification mode */ + + unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ + unsigned long ctx_all_pmds[4]; /* bitmask of all accessible PMDs */ + unsigned long ctx_reload_pmds[4]; /* bitmask of force reload PMD on ctxsw in */ + + unsigned long ctx_all_pmcs[4]; /* bitmask of all accessible PMCs */ + unsigned long ctx_reload_pmcs[4]; /* bitmask of force reload PMC on ctxsw in */ + unsigned long ctx_used_monitors[4]; /* bitmask of monitor PMC being used */ + + unsigned long ctx_pmcs[IA64_NUM_PMC_REGS]; /* saved copies of PMC values */ + + unsigned int ctx_used_ibrs[1]; /* bitmask of used IBR (speedup ctxsw in) */ + unsigned int ctx_used_dbrs[1]; /* bitmask of used DBR (speedup ctxsw in) */ + unsigned long ctx_dbrs[IA64_NUM_DBG_REGS]; /* DBR values (cache) when not loaded */ + unsigned long ctx_ibrs[IA64_NUM_DBG_REGS]; /* IBR values (cache) when not loaded */ + + pfm_counter_t ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */ + + u64 ctx_saved_psr_up; /* only contains psr.up value */ + + unsigned long ctx_last_activation; /* context last activation number for last_cpu */ + unsigned int ctx_last_cpu; /* CPU id of current or last CPU used (SMP only) */ + unsigned int ctx_cpu; /* cpu to which perfmon is applied (system wide) */ + + int ctx_fd; /* file descriptor used my this context */ + pfm_ovfl_arg_t ctx_ovfl_arg; /* argument to custom buffer format handler */ + + pfm_buffer_fmt_t *ctx_buf_fmt; /* buffer format callbacks */ + void *ctx_smpl_hdr; /* points to sampling buffer header kernel vaddr */ + unsigned long ctx_smpl_size; /* size of sampling buffer */ + void *ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ + + wait_queue_head_t ctx_msgq_wait; + pfm_msg_t ctx_msgq[PFM_MAX_MSGS]; + int ctx_msgq_head; + int ctx_msgq_tail; + struct fasync_struct *ctx_async_queue; + + wait_queue_head_t ctx_zombieq; /* termination cleanup wait queue */ +} pfm_context_t; + +/* + * magic number used to verify that structure is really + * a perfmon context + */ +#define PFM_IS_FILE(f) ((f)->f_op == &pfm_file_ops) + +#define PFM_GET_CTX(t) ((pfm_context_t *)(t)->thread.pfm_context) + +#ifdef CONFIG_SMP +#define SET_LAST_CPU(ctx, v) (ctx)->ctx_last_cpu = (v) +#define GET_LAST_CPU(ctx) (ctx)->ctx_last_cpu +#else +#define SET_LAST_CPU(ctx, v) do {} while(0) +#define GET_LAST_CPU(ctx) do {} while(0) +#endif + + +#define ctx_fl_block ctx_flags.block +#define ctx_fl_system ctx_flags.system +#define ctx_fl_using_dbreg ctx_flags.using_dbreg +#define ctx_fl_is_sampling ctx_flags.is_sampling +#define ctx_fl_excl_idle ctx_flags.excl_idle +#define ctx_fl_going_zombie ctx_flags.going_zombie +#define ctx_fl_trap_reason ctx_flags.trap_reason +#define ctx_fl_no_msg ctx_flags.no_msg +#define ctx_fl_can_restart ctx_flags.can_restart + +#define PFM_SET_WORK_PENDING(t, v) do { (t)->thread.pfm_needs_checking = v; } while(0); +#define PFM_GET_WORK_PENDING(t) (t)->thread.pfm_needs_checking + +/* + * global information about all sessions + * mostly used to synchronize between system wide and per-process + */ +typedef struct { + spinlock_t pfs_lock; /* lock the structure */ + + unsigned int pfs_task_sessions; /* number of per task sessions */ + unsigned int pfs_sys_sessions; /* number of per system wide sessions */ + unsigned int pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ + unsigned int pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ + struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ +} pfm_session_t; + +/* + * information about a PMC or PMD. + * dep_pmd[]: a bitmask of dependent PMD registers + * dep_pmc[]: a bitmask of dependent PMC registers + */ +typedef int (*pfm_reg_check_t)(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs); +typedef struct { + unsigned int type; + int pm_pos; + unsigned long default_value; /* power-on default value */ + unsigned long reserved_mask; /* bitmask of reserved bits */ + pfm_reg_check_t read_check; + pfm_reg_check_t write_check; + unsigned long dep_pmd[4]; + unsigned long dep_pmc[4]; +} pfm_reg_desc_t; + +/* assume cnum is a valid monitor */ +#define PMC_PM(cnum, val) (((val) >> (pmu_conf->pmc_desc[cnum].pm_pos)) & 0x1) + +/* + * This structure is initialized at boot time and contains + * a description of the PMU main characteristics. + * + * If the probe function is defined, detection is based + * on its return value: + * - 0 means recognized PMU + * - anything else means not supported + * When the probe function is not defined, then the pmu_family field + * is used and it must match the host CPU family such that: + * - cpu->family & config->pmu_family != 0 + */ +typedef struct { + unsigned long ovfl_val; /* overflow value for counters */ + + pfm_reg_desc_t *pmc_desc; /* detailed PMC register dependencies descriptions */ + pfm_reg_desc_t *pmd_desc; /* detailed PMD register dependencies descriptions */ + + unsigned int num_pmcs; /* number of PMCS: computed at init time */ + unsigned int num_pmds; /* number of PMDS: computed at init time */ + unsigned long impl_pmcs[4]; /* bitmask of implemented PMCS */ + unsigned long impl_pmds[4]; /* bitmask of implemented PMDS */ + + char *pmu_name; /* PMU family name */ + unsigned int pmu_family; /* cpuid family pattern used to identify pmu */ + unsigned int flags; /* pmu specific flags */ + unsigned int num_ibrs; /* number of IBRS: computed at init time */ + unsigned int num_dbrs; /* number of DBRS: computed at init time */ + unsigned int num_counters; /* PMC/PMD counting pairs : computed at init time */ + int (*probe)(void); /* customized probe routine */ + unsigned int use_rr_dbregs:1; /* set if debug registers used for range restriction */ +} pmu_config_t; +/* + * PMU specific flags + */ +#define PFM_PMU_IRQ_RESEND 1 /* PMU needs explicit IRQ resend */ + +/* + * debug register related type definitions + */ +typedef struct { + unsigned long ibr_mask:56; + unsigned long ibr_plm:4; + unsigned long ibr_ig:3; + unsigned long ibr_x:1; +} ibr_mask_reg_t; + +typedef struct { + unsigned long dbr_mask:56; + unsigned long dbr_plm:4; + unsigned long dbr_ig:2; + unsigned long dbr_w:1; + unsigned long dbr_r:1; +} dbr_mask_reg_t; + +typedef union { + unsigned long val; + ibr_mask_reg_t ibr; + dbr_mask_reg_t dbr; +} dbreg_t; + + +/* + * perfmon command descriptions + */ +typedef struct { + int (*cmd_func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + char *cmd_name; + int cmd_flags; + unsigned int cmd_narg; + size_t cmd_argsize; + int (*cmd_getsize)(void *arg, size_t *sz); +} pfm_cmd_desc_t; + +#define PFM_CMD_FD 0x01 /* command requires a file descriptor */ +#define PFM_CMD_ARG_READ 0x02 /* command must read argument(s) */ +#define PFM_CMD_ARG_RW 0x04 /* command must read/write argument(s) */ +#define PFM_CMD_STOP 0x08 /* command does not work on zombie context */ + + +#define PFM_CMD_NAME(cmd) pfm_cmd_tab[(cmd)].cmd_name +#define PFM_CMD_READ_ARG(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_ARG_READ) +#define PFM_CMD_RW_ARG(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_ARG_RW) +#define PFM_CMD_USE_FD(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_FD) +#define PFM_CMD_STOPPED(cmd) (pfm_cmd_tab[(cmd)].cmd_flags & PFM_CMD_STOP) + +#define PFM_CMD_ARG_MANY -1 /* cannot be zero */ + +typedef struct { + unsigned long pfm_spurious_ovfl_intr_count; /* keep track of spurious ovfl interrupts */ + unsigned long pfm_replay_ovfl_intr_count; /* keep track of replayed ovfl interrupts */ + unsigned long pfm_ovfl_intr_count; /* keep track of ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles; /* cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_min; /* min cycles spent processing ovfl interrupts */ + unsigned long pfm_ovfl_intr_cycles_max; /* max cycles spent processing ovfl interrupts */ + unsigned long pfm_smpl_handler_calls; + unsigned long pfm_smpl_handler_cycles; + char pad[SMP_CACHE_BYTES] ____cacheline_aligned; +} pfm_stats_t; + +/* + * perfmon internal variables + */ +static pfm_stats_t pfm_stats[NR_CPUS]; +static pfm_session_t pfm_sessions; /* global sessions information */ + +static DEFINE_SPINLOCK(pfm_alt_install_check); +static pfm_intr_handler_desc_t *pfm_alt_intr_handler; + +static struct proc_dir_entry *perfmon_dir; +static pfm_uuid_t pfm_null_uuid = {0,}; + +static spinlock_t pfm_buffer_fmt_lock; +static LIST_HEAD(pfm_buffer_fmt_list); + +static pmu_config_t *pmu_conf; + +/* sysctl() controls */ +pfm_sysctl_t pfm_sysctl; +EXPORT_SYMBOL(pfm_sysctl); + +static ctl_table pfm_ctl_table[]={ + {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, + {3, "fastctxsw", &pfm_sysctl.fastctxsw, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, + {4, "expert_mode", &pfm_sysctl.expert_mode, sizeof(int), 0600, NULL, &proc_dointvec, NULL,}, + { 0, }, +}; +static ctl_table pfm_sysctl_dir[] = { + {1, "perfmon", NULL, 0, 0755, pfm_ctl_table, }, + {0,}, +}; +static ctl_table pfm_sysctl_root[] = { + {1, "kernel", NULL, 0, 0755, pfm_sysctl_dir, }, + {0,}, +}; +static struct ctl_table_header *pfm_sysctl_header; + +static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); +static int pfm_flush(struct file *filp); + +#define pfm_get_cpu_var(v) __ia64_per_cpu_var(v) +#define pfm_get_cpu_data(a,b) per_cpu(a, b) + +static inline void +pfm_put_task(struct task_struct *task) +{ + if (task != current) put_task_struct(task); +} + +static inline void +pfm_set_task_notify(struct task_struct *task) +{ + struct thread_info *info; + + info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE); + set_bit(TIF_NOTIFY_RESUME, &info->flags); +} + +static inline void +pfm_clear_task_notify(void) +{ + clear_thread_flag(TIF_NOTIFY_RESUME); +} + +static inline void +pfm_reserve_page(unsigned long a) +{ + SetPageReserved(vmalloc_to_page((void *)a)); +} +static inline void +pfm_unreserve_page(unsigned long a) +{ + ClearPageReserved(vmalloc_to_page((void*)a)); +} + +static inline unsigned long +pfm_protect_ctx_ctxsw(pfm_context_t *x) +{ + spin_lock(&(x)->ctx_lock); + return 0UL; +} + +static inline void +pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) +{ + spin_unlock(&(x)->ctx_lock); +} + +static inline unsigned int +pfm_do_munmap(struct mm_struct *mm, unsigned long addr, size_t len, int acct) +{ + return do_munmap(mm, addr, len); +} + +static inline unsigned long +pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, unsigned long exec) +{ + return get_unmapped_area(file, addr, len, pgoff, flags); +} + + +static struct super_block * +pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) +{ + return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); +} + +static struct file_system_type pfm_fs_type = { + .name = "pfmfs", + .get_sb = pfmfs_get_sb, + .kill_sb = kill_anon_super, +}; + +DEFINE_PER_CPU(unsigned long, pfm_syst_info); +DEFINE_PER_CPU(struct task_struct *, pmu_owner); +DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); +DEFINE_PER_CPU(unsigned long, pmu_activation_number); +EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info); + + +/* forward declaration */ +static struct file_operations pfm_file_ops; + +/* + * forward declarations + */ +#ifndef CONFIG_SMP +static void pfm_lazy_save_regs (struct task_struct *ta); +#endif + +void dump_pmu_state(const char *); +static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + +#include "perfmon_itanium.h" +#include "perfmon_mckinley.h" +#include "perfmon_montecito.h" +#include "perfmon_generic.h" + +static pmu_config_t *pmu_confs[]={ + &pmu_conf_mont, + &pmu_conf_mck, + &pmu_conf_ita, + &pmu_conf_gen, /* must be last */ + NULL +}; + + +static int pfm_end_notify_user(pfm_context_t *ctx); + +static inline void +pfm_clear_psr_pp(void) +{ + ia64_rsm(IA64_PSR_PP); + ia64_srlz_i(); +} + +static inline void +pfm_set_psr_pp(void) +{ + ia64_ssm(IA64_PSR_PP); + ia64_srlz_i(); +} + +static inline void +pfm_clear_psr_up(void) +{ + ia64_rsm(IA64_PSR_UP); + ia64_srlz_i(); +} + +static inline void +pfm_set_psr_up(void) +{ + ia64_ssm(IA64_PSR_UP); + ia64_srlz_i(); +} + +static inline unsigned long +pfm_get_psr(void) +{ + unsigned long tmp; + tmp = ia64_getreg(_IA64_REG_PSR); + ia64_srlz_i(); + return tmp; +} + +static inline void +pfm_set_psr_l(unsigned long val) +{ + ia64_setreg(_IA64_REG_PSR_L, val); + ia64_srlz_i(); +} + +static inline void +pfm_freeze_pmu(void) +{ + ia64_set_pmc(0,1UL); + ia64_srlz_d(); +} + +static inline void +pfm_unfreeze_pmu(void) +{ + ia64_set_pmc(0,0UL); + ia64_srlz_d(); +} + +static inline void +pfm_restore_ibrs(unsigned long *ibrs, unsigned int nibrs) +{ + int i; + + for (i=0; i < nibrs; i++) { + ia64_set_ibr(i, ibrs[i]); + ia64_dv_serialize_instruction(); + } + ia64_srlz_i(); +} + +static inline void +pfm_restore_dbrs(unsigned long *dbrs, unsigned int ndbrs) +{ + int i; + + for (i=0; i < ndbrs; i++) { + ia64_set_dbr(i, dbrs[i]); + ia64_dv_serialize_data(); + } + ia64_srlz_d(); +} + +/* + * PMD[i] must be a counter. no check is made + */ +static inline unsigned long +pfm_read_soft_counter(pfm_context_t *ctx, int i) +{ + return ctx->ctx_pmds[i].val + (ia64_get_pmd(i) & pmu_conf->ovfl_val); +} + +/* + * PMD[i] must be a counter. no check is made + */ +static inline void +pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) +{ + unsigned long ovfl_val = pmu_conf->ovfl_val; + + ctx->ctx_pmds[i].val = val & ~ovfl_val; + /* + * writing to unimplemented part is ignore, so we do not need to + * mask off top part + */ + ia64_set_pmd(i, val & ovfl_val); +} + +static pfm_msg_t * +pfm_get_new_msg(pfm_context_t *ctx) +{ + int idx, next; + + next = (ctx->ctx_msgq_tail+1) % PFM_MAX_MSGS; + + DPRINT(("ctx_fd=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + if (next == ctx->ctx_msgq_head) return NULL; + + idx = ctx->ctx_msgq_tail; + ctx->ctx_msgq_tail = next; + + DPRINT(("ctx=%p head=%d tail=%d msg=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, idx)); + + return ctx->ctx_msgq+idx; +} + +static pfm_msg_t * +pfm_get_next_msg(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + DPRINT(("ctx=%p head=%d tail=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + if (PFM_CTXQ_EMPTY(ctx)) return NULL; + + /* + * get oldest message + */ + msg = ctx->ctx_msgq+ctx->ctx_msgq_head; + + /* + * and move forward + */ + ctx->ctx_msgq_head = (ctx->ctx_msgq_head+1) % PFM_MAX_MSGS; + + DPRINT(("ctx=%p head=%d tail=%d type=%d\n", ctx, ctx->ctx_msgq_head, ctx->ctx_msgq_tail, msg->pfm_gen_msg.msg_type)); + + return msg; +} + +static void +pfm_reset_msgq(pfm_context_t *ctx) +{ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + DPRINT(("ctx=%p msgq reset\n", ctx)); +} + +static void * +pfm_rvmalloc(unsigned long size) +{ + void *mem; + unsigned long addr; + + size = PAGE_ALIGN(size); + mem = vmalloc(size); + if (mem) { + //printk("perfmon: CPU%d pfm_rvmalloc(%ld)=%p\n", smp_processor_id(), size, mem); + memset(mem, 0, size); + addr = (unsigned long)mem; + while (size > 0) { + pfm_reserve_page(addr); + addr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void +pfm_rvfree(void *mem, unsigned long size) +{ + unsigned long addr; + + if (mem) { + DPRINT(("freeing physical buffer @%p size=%lu\n", mem, size)); + addr = (unsigned long) mem; + while ((long) size > 0) { + pfm_unreserve_page(addr); + addr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } + return; +} + +static pfm_context_t * +pfm_context_alloc(void) +{ + pfm_context_t *ctx; + + /* + * allocate context descriptor + * must be able to free with interrupts disabled + */ + ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL); + if (ctx) { + memset(ctx, 0, sizeof(pfm_context_t)); + DPRINT(("alloc ctx @%p\n", ctx)); + } + return ctx; +} + +static void +pfm_context_free(pfm_context_t *ctx) +{ + if (ctx) { + DPRINT(("free ctx @%p\n", ctx)); + kfree(ctx); + } +} + +static void +pfm_mask_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask, val, ovfl_mask; + int i; + + DPRINT_ovfl(("masking monitoring for [%d]\n", task->pid)); + + ovfl_mask = pmu_conf->ovfl_val; + /* + * monitoring can only be masked as a result of a valid + * counter overflow. In UP, it means that the PMU still + * has an owner. Note that the owner can be different + * from the current task. However the PMU state belongs + * to the owner. + * In SMP, a valid overflow only happens when task is + * current. Therefore if we come here, we know that + * the PMU state belongs to the current task, therefore + * we can access the live registers. + * + * So in both cases, the live register contains the owner's + * state. We can ONLY touch the PMU registers and NOT the PSR. + * + * As a consequence to this call, the thread->pmds[] array + * contains stale information which must be ignored + * when context is reloaded AND monitoring is active (see + * pfm_restart). + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + val = ia64_get_pmd(i); + + if (PMD_IS_COUNTING(i)) { + /* + * we rebuild the full 64 bit value of the counter + */ + ctx->ctx_pmds[i].val += (val & ovfl_mask); + } else { + ctx->ctx_pmds[i].val = val; + } + DPRINT_ovfl(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val & ovfl_mask)); + } + /* + * mask monitoring by setting the privilege level to 0 + * we cannot use psr.pp/psr.up for this, it is controlled by + * the user + * + * if task is current, modify actual registers, otherwise modify + * thread save state, i.e., what will be restored in pfm_load_regs() + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + ia64_set_pmc(i, th->pmcs[i] & ~0xfUL); + th->pmcs[i] &= ~0xfUL; + DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, th->pmcs[i])); + } + /* + * make all of this visible + */ + ia64_srlz_d(); +} + +/* + * must always be done with task == current + * + * context must be in MASKED state when calling + */ +static void +pfm_restore_monitoring(struct task_struct *task) +{ + pfm_context_t *ctx = PFM_GET_CTX(task); + struct thread_struct *th = &task->thread; + unsigned long mask, ovfl_mask; + unsigned long psr, val; + int i, is_system; + + is_system = ctx->ctx_fl_system; + ovfl_mask = pmu_conf->ovfl_val; + + if (task != current) { + printk(KERN_ERR "perfmon.%d: invalid task[%d] current[%d]\n", __LINE__, task->pid, current->pid); + return; + } + if (ctx->ctx_state != PFM_CTX_MASKED) { + printk(KERN_ERR "perfmon.%d: task[%d] current[%d] invalid state=%d\n", __LINE__, + task->pid, current->pid, ctx->ctx_state); + return; + } + psr = pfm_get_psr(); + /* + * monitoring is masked via the PMC. + * As we restore their value, we do not want each counter to + * restart right away. We stop monitoring using the PSR, + * restore the PMC (and PMD) and then re-establish the psr + * as it was. Note that there can be no pending overflow at + * this point, because monitoring was MASKED. + * + * system-wide session are pinned and self-monitoring + */ + if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* disable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + } else { + pfm_clear_psr_up(); + } + /* + * first, we restore the PMD + */ + mask = ctx->ctx_used_pmds[0]; + for (i = 0; mask; i++, mask>>=1) { + /* skip non used pmds */ + if ((mask & 0x1) == 0) continue; + + if (PMD_IS_COUNTING(i)) { + /* + * we split the 64bit value according to + * counter width + */ + val = ctx->ctx_pmds[i].val & ovfl_mask; + ctx->ctx_pmds[i].val &= ~ovfl_mask; + } else { + val = ctx->ctx_pmds[i].val; + } + ia64_set_pmd(i, val); + + DPRINT(("pmd[%d]=0x%lx hw_pmd=0x%lx\n", + i, + ctx->ctx_pmds[i].val, + val)); + } + /* + * restore the PMCs + */ + mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER; + for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0UL) continue; + th->pmcs[i] = ctx->ctx_pmcs[i]; + ia64_set_pmc(i, th->pmcs[i]); + DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i])); + } + ia64_srlz_d(); + + /* + * must restore DBR/IBR because could be modified while masked + * XXX: need to optimize + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + + /* + * now restore PSR + */ + if (is_system && (PFM_CPUINFO_GET() & PFM_CPUINFO_DCR_PP)) { + /* enable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP); + ia64_srlz_i(); + } + pfm_set_psr_l(psr); +} + +static inline void +pfm_save_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + + ia64_srlz_d(); + + for (i=0; mask; i++, mask>>=1) { + if (mask & 0x1) pmds[i] = ia64_get_pmd(i); + } +} + +/* + * reload from thread state (used for ctxw only) + */ +static inline void +pfm_restore_pmds(unsigned long *pmds, unsigned long mask) +{ + int i; + unsigned long val, ovfl_val = pmu_conf->ovfl_val; + + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + val = PMD_IS_COUNTING(i) ? pmds[i] & ovfl_val : pmds[i]; + ia64_set_pmd(i, val); + } + ia64_srlz_d(); +} + +/* + * propagate PMD from context to thread-state + */ +static inline void +pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long ovfl_val = pmu_conf->ovfl_val; + unsigned long mask = ctx->ctx_all_pmds[0]; + unsigned long val; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + + val = ctx->ctx_pmds[i].val; + + /* + * We break up the 64 bit value into 2 pieces + * the lower bits go to the machine state in the + * thread (will be reloaded on ctxsw in). + * The upper part stays in the soft-counter. + */ + if (PMD_IS_COUNTING(i)) { + ctx->ctx_pmds[i].val = val & ~ovfl_val; + val &= ovfl_val; + } + thread->pmds[i] = val; + + DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n", + i, + thread->pmds[i], + ctx->ctx_pmds[i].val)); + } +} + +/* + * propagate PMC from context to thread-state + */ +static inline void +pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx) +{ + struct thread_struct *thread = &task->thread; + unsigned long mask = ctx->ctx_all_pmcs[0]; + int i; + + DPRINT(("mask=0x%lx\n", mask)); + + for (i=0; mask; i++, mask>>=1) { + /* masking 0 with ovfl_val yields 0 */ + thread->pmcs[i] = ctx->ctx_pmcs[i]; + DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i])); + } +} + + + +static inline void +pfm_restore_pmcs(unsigned long *pmcs, unsigned long mask) +{ + int i; + + for (i=0; mask; i++, mask>>=1) { + if ((mask & 0x1) == 0) continue; + ia64_set_pmc(i, pmcs[i]); + } + ia64_srlz_d(); +} + +static inline int +pfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b) +{ + return memcmp(a, b, sizeof(pfm_uuid_t)); +} + +static inline int +pfm_buf_fmt_exit(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_exit) ret = (*fmt->fmt_exit)(task, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_getsize(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size) +{ + int ret = 0; + if (fmt->fmt_getsize) ret = (*fmt->fmt_getsize)(task, flags, cpu, arg, size); + return ret; +} + + +static inline int +pfm_buf_fmt_validate(pfm_buffer_fmt_t *fmt, struct task_struct *task, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_validate) ret = (*fmt->fmt_validate)(task, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_init(pfm_buffer_fmt_t *fmt, struct task_struct *task, void *buf, unsigned int flags, + int cpu, void *arg) +{ + int ret = 0; + if (fmt->fmt_init) ret = (*fmt->fmt_init)(task, buf, flags, cpu, arg); + return ret; +} + +static inline int +pfm_buf_fmt_restart(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart) ret = (*fmt->fmt_restart)(task, ctrl, buf, regs); + return ret; +} + +static inline int +pfm_buf_fmt_restart_active(pfm_buffer_fmt_t *fmt, struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs) +{ + int ret = 0; + if (fmt->fmt_restart_active) ret = (*fmt->fmt_restart_active)(task, ctrl, buf, regs); + return ret; +} + +static pfm_buffer_fmt_t * +__pfm_find_buffer_fmt(pfm_uuid_t uuid) +{ + struct list_head * pos; + pfm_buffer_fmt_t * entry; + + list_for_each(pos, &pfm_buffer_fmt_list) { + entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list); + if (pfm_uuid_cmp(uuid, entry->fmt_uuid) == 0) + return entry; + } + return NULL; +} + +/* + * find a buffer format based on its uuid + */ +static pfm_buffer_fmt_t * +pfm_find_buffer_fmt(pfm_uuid_t uuid) +{ + pfm_buffer_fmt_t * fmt; + spin_lock(&pfm_buffer_fmt_lock); + fmt = __pfm_find_buffer_fmt(uuid); + spin_unlock(&pfm_buffer_fmt_lock); + return fmt; +} + +int +pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt) +{ + int ret = 0; + + /* some sanity checks */ + if (fmt == NULL || fmt->fmt_name == NULL) return -EINVAL; + + /* we need at least a handler */ + if (fmt->fmt_handler == NULL) return -EINVAL; + + /* + * XXX: need check validity of fmt_arg_size + */ + + spin_lock(&pfm_buffer_fmt_lock); + + if (__pfm_find_buffer_fmt(fmt->fmt_uuid)) { + printk(KERN_ERR "perfmon: duplicate sampling format: %s\n", fmt->fmt_name); + ret = -EBUSY; + goto out; + } + list_add(&fmt->fmt_list, &pfm_buffer_fmt_list); + printk(KERN_INFO "perfmon: added sampling format %s\n", fmt->fmt_name); + +out: + spin_unlock(&pfm_buffer_fmt_lock); + return ret; +} +EXPORT_SYMBOL(pfm_register_buffer_fmt); + +int +pfm_unregister_buffer_fmt(pfm_uuid_t uuid) +{ + pfm_buffer_fmt_t *fmt; + int ret = 0; + + spin_lock(&pfm_buffer_fmt_lock); + + fmt = __pfm_find_buffer_fmt(uuid); + if (!fmt) { + printk(KERN_ERR "perfmon: cannot unregister format, not found\n"); + ret = -EINVAL; + goto out; + } + list_del_init(&fmt->fmt_list); + printk(KERN_INFO "perfmon: removed sampling format: %s\n", fmt->fmt_name); + +out: + spin_unlock(&pfm_buffer_fmt_lock); + return ret; + +} +EXPORT_SYMBOL(pfm_unregister_buffer_fmt); + +extern void update_pal_halt_status(int); + +static int +pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) +{ + unsigned long flags; + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(flags); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + if (is_syswide) { + /* + * cannot mix system wide and per-task sessions + */ + if (pfm_sessions.pfs_task_sessions > 0UL) { + DPRINT(("system wide not possible, %u conflicting task_sessions\n", + pfm_sessions.pfs_task_sessions)); + goto abort; + } + + if (pfm_sessions.pfs_sys_session[cpu]) goto error_conflict; + + DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id())); + + pfm_sessions.pfs_sys_session[cpu] = task; + + pfm_sessions.pfs_sys_sessions++ ; + + } else { + if (pfm_sessions.pfs_sys_sessions) goto abort; + pfm_sessions.pfs_task_sessions++; + } + + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + /* + * disable default_idle() to go to PAL_HALT + */ + update_pal_halt_status(0); + + UNLOCK_PFS(flags); + + return 0; + +error_conflict: + DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", + pfm_sessions.pfs_sys_session[cpu]->pid, + cpu)); +abort: + UNLOCK_PFS(flags); + + return -EBUSY; + +} + +static int +pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu) +{ + unsigned long flags; + /* + * validy checks on cpu_mask have been done upstream + */ + LOCK_PFS(flags); + + DPRINT(("in sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + + if (is_syswide) { + pfm_sessions.pfs_sys_session[cpu] = NULL; + /* + * would not work with perfmon+more than one bit in cpu_mask + */ + if (ctx && ctx->ctx_fl_using_dbreg) { + if (pfm_sessions.pfs_sys_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for ctx %p sys_use_dbregs=0\n", ctx); + } else { + pfm_sessions.pfs_sys_use_dbregs--; + } + } + pfm_sessions.pfs_sys_sessions--; + } else { + pfm_sessions.pfs_task_sessions--; + } + DPRINT(("out sys_sessions=%u task_sessions=%u dbregs=%u syswide=%d cpu=%u\n", + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_use_dbregs, + is_syswide, + cpu)); + + /* + * if possible, enable default_idle() to go into PAL_HALT + */ + if (pfm_sessions.pfs_task_sessions == 0 && pfm_sessions.pfs_sys_sessions == 0) + update_pal_halt_status(1); + + UNLOCK_PFS(flags); + + return 0; +} + +/* + * removes virtual mapping of the sampling buffer. + * IMPORTANT: cannot be called with interrupts disable, e.g. inside + * a PROTECT_CTX() section. + */ +static int +pfm_remove_smpl_mapping(struct task_struct *task, void *vaddr, unsigned long size) +{ + int r; + + /* sanity checks */ + if (task->mm == NULL || size == 0UL || vaddr == NULL) { + printk(KERN_ERR "perfmon: pfm_remove_smpl_mapping [%d] invalid context mm=%p\n", task->pid, task->mm); + return -EINVAL; + } + + DPRINT(("smpl_vaddr=%p size=%lu\n", vaddr, size)); + + /* + * does the actual unmapping + */ + down_write(&task->mm->mmap_sem); + + DPRINT(("down_write done smpl_vaddr=%p size=%lu\n", vaddr, size)); + + r = pfm_do_munmap(task->mm, (unsigned long)vaddr, size, 0); + + up_write(&task->mm->mmap_sem); + if (r !=0) { + printk(KERN_ERR "perfmon: [%d] unable to unmap sampling buffer @%p size=%lu\n", task->pid, vaddr, size); + } + + DPRINT(("do_unmap(%p, %lu)=%d\n", vaddr, size, r)); + + return 0; +} + +/* + * free actual physical storage used by sampling buffer + */ +#if 0 +static int +pfm_free_smpl_buffer(pfm_context_t *ctx) +{ + pfm_buffer_fmt_t *fmt; + + if (ctx->ctx_smpl_hdr == NULL) goto invalid_free; + + /* + * we won't use the buffer format anymore + */ + fmt = ctx->ctx_buf_fmt; + + DPRINT(("sampling buffer @%p size %lu vaddr=%p\n", + ctx->ctx_smpl_hdr, + ctx->ctx_smpl_size, + ctx->ctx_smpl_vaddr)); + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + + /* + * free the buffer + */ + pfm_rvfree(ctx->ctx_smpl_hdr, ctx->ctx_smpl_size); + + ctx->ctx_smpl_hdr = NULL; + ctx->ctx_smpl_size = 0UL; + + return 0; + +invalid_free: + printk(KERN_ERR "perfmon: pfm_free_smpl_buffer [%d] no buffer\n", current->pid); + return -EINVAL; +} +#endif + +static inline void +pfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt) +{ + if (fmt == NULL) return; + + pfm_buf_fmt_exit(fmt, current, NULL, NULL); + +} + +/* + * pfmfs should _never_ be mounted by userland - too much of security hassle, + * no real gain from having the whole whorehouse mounted. So we don't need + * any operations on the root directory. However, we need a non-trivial + * d_name - pfm: will go nicely and kill the special-casing in procfs. + */ +static struct vfsmount *pfmfs_mnt; + +static int __init +init_pfm_fs(void) +{ + int err = register_filesystem(&pfm_fs_type); + if (!err) { + pfmfs_mnt = kern_mount(&pfm_fs_type); + err = PTR_ERR(pfmfs_mnt); + if (IS_ERR(pfmfs_mnt)) + unregister_filesystem(&pfm_fs_type); + else + err = 0; + } + return err; +} + +static void __exit +exit_pfm_fs(void) +{ + unregister_filesystem(&pfm_fs_type); + mntput(pfmfs_mnt); +} + +static ssize_t +pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) +{ + pfm_context_t *ctx; + pfm_msg_t *msg; + ssize_t ret; + unsigned long flags; + DECLARE_WAITQUEUE(wait, current); + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return -EINVAL; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", current->pid); + return -EINVAL; + } + + /* + * check even when there is no message + */ + if (size < sizeof(pfm_msg_t)) { + DPRINT(("message is too small ctx=%p (>=%ld)\n", ctx, sizeof(pfm_msg_t))); + return -EINVAL; + } + + PROTECT_CTX(ctx, flags); + + /* + * put ourselves on the wait queue + */ + add_wait_queue(&ctx->ctx_msgq_wait, &wait); + + + for(;;) { + /* + * check wait queue + */ + + set_current_state(TASK_INTERRUPTIBLE); + + DPRINT(("head=%d tail=%d\n", ctx->ctx_msgq_head, ctx->ctx_msgq_tail)); + + ret = 0; + if(PFM_CTXQ_EMPTY(ctx) == 0) break; + + UNPROTECT_CTX(ctx, flags); + + /* + * check non-blocking read + */ + ret = -EAGAIN; + if(filp->f_flags & O_NONBLOCK) break; + + /* + * check pending signals + */ + if(signal_pending(current)) { + ret = -EINTR; + break; + } + /* + * no message, so wait + */ + schedule(); + + PROTECT_CTX(ctx, flags); + } + DPRINT(("[%d] back to running ret=%ld\n", current->pid, ret)); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctx->ctx_msgq_wait, &wait); + + if (ret < 0) goto abort; + + ret = -EINVAL; + msg = pfm_get_next_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_read no msg for ctx=%p [%d]\n", ctx, current->pid); + goto abort_locked; + } + + DPRINT(("fd=%d type=%d\n", msg->pfm_gen_msg.msg_ctx_fd, msg->pfm_gen_msg.msg_type)); + + ret = -EFAULT; + if(copy_to_user(buf, msg, sizeof(pfm_msg_t)) == 0) ret = sizeof(pfm_msg_t); + +abort_locked: + UNPROTECT_CTX(ctx, flags); +abort: + return ret; +} + +static ssize_t +pfm_write(struct file *file, const char __user *ubuf, + size_t size, loff_t *ppos) +{ + DPRINT(("pfm_write called\n")); + return -EINVAL; +} + +static unsigned int +pfm_poll(struct file *filp, poll_table * wait) +{ + pfm_context_t *ctx; + unsigned long flags; + unsigned int mask = 0; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); + return 0; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", current->pid); + return 0; + } + + + DPRINT(("pfm_poll ctx_fd=%d before poll_wait\n", ctx->ctx_fd)); + + poll_wait(filp, &ctx->ctx_msgq_wait, wait); + + PROTECT_CTX(ctx, flags); + + if (PFM_CTXQ_EMPTY(ctx) == 0) + mask = POLLIN | POLLRDNORM; + + UNPROTECT_CTX(ctx, flags); + + DPRINT(("pfm_poll ctx_fd=%d mask=0x%x\n", ctx->ctx_fd, mask)); + + return mask; +} + +static int +pfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + DPRINT(("pfm_ioctl called\n")); + return -EINVAL; +} + +/* + * interrupt cannot be masked when coming here + */ +static inline int +pfm_do_fasync(int fd, struct file *filp, pfm_context_t *ctx, int on) +{ + int ret; + + ret = fasync_helper (fd, filp, on, &ctx->ctx_async_queue); + + DPRINT(("pfm_fasync called by [%d] on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + current->pid, + fd, + on, + ctx->ctx_async_queue, ret)); + + return ret; +} + +static int +pfm_fasync(int fd, struct file *filp, int on) +{ + pfm_context_t *ctx; + int ret; + + if (PFM_IS_FILE(filp) == 0) { + printk(KERN_ERR "perfmon: pfm_fasync bad magic [%d]\n", current->pid); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", current->pid); + return -EBADF; + } + /* + * we cannot mask interrupts during this call because this may + * may go to sleep if memory is not readily avalaible. + * + * We are protected from the conetxt disappearing by the get_fd()/put_fd() + * done in caller. Serialization of this function is ensured by caller. + */ + ret = pfm_do_fasync(fd, filp, ctx, on); + + + DPRINT(("pfm_fasync called on ctx_fd=%d on=%d async_queue=%p ret=%d\n", + fd, + on, + ctx->ctx_async_queue, ret)); + + return ret; +} + +#ifdef CONFIG_SMP +/* + * this function is exclusively called from pfm_close(). + * The context is not protected at that time, nor are interrupts + * on the remote CPU. That's necessary to avoid deadlocks. + */ +static void +pfm_syswide_force_stop(void *info) +{ + pfm_context_t *ctx = (pfm_context_t *)info; + struct pt_regs *regs = task_pt_regs(current); + struct task_struct *owner; + unsigned long flags; + int ret; + + if (ctx->ctx_cpu != smp_processor_id()) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop for CPU%d but on CPU%d\n", + ctx->ctx_cpu, + smp_processor_id()); + return; + } + owner = GET_PMU_OWNER(); + if (owner != ctx->ctx_task) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected owner [%d] instead of [%d]\n", + smp_processor_id(), + owner->pid, ctx->ctx_task->pid); + return; + } + if (GET_PMU_CTX() != ctx) { + printk(KERN_ERR "perfmon: pfm_syswide_force_stop CPU%d unexpected ctx %p instead of %p\n", + smp_processor_id(), + GET_PMU_CTX(), ctx); + return; + } + + DPRINT(("on CPU%d forcing system wide stop for [%d]\n", smp_processor_id(), ctx->ctx_task->pid)); + /* + * the context is already protected in pfm_close(), we simply + * need to mask interrupts to avoid a PMU interrupt race on + * this CPU + */ + local_irq_save(flags); + + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + DPRINT(("context_unload returned %d\n", ret)); + } + + /* + * unmask interrupts, PMU interrupts are now spurious here + */ + local_irq_restore(flags); +} + +static void +pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx) +{ + int ret; + + DPRINT(("calling CPU%d for cleanup\n", ctx->ctx_cpu)); + ret = smp_call_function_single(ctx->ctx_cpu, pfm_syswide_force_stop, ctx, 0, 1); + DPRINT(("called CPU%d for cleanup ret=%d\n", ctx->ctx_cpu, ret)); +} +#endif /* CONFIG_SMP */ + +/* + * called for each close(). Partially free resources. + * When caller is self-monitoring, the context is unloaded. + */ +static int +pfm_flush(struct file *filp) +{ + pfm_context_t *ctx; + struct task_struct *task; + struct pt_regs *regs; + unsigned long flags; + unsigned long smpl_buf_size = 0UL; + void *smpl_buf_vaddr = NULL; + int state, is_system; + + if (PFM_IS_FILE(filp) == 0) { + DPRINT(("bad magic for\n")); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_flush: NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + /* + * remove our file from the async queue, if we use this mode. + * This can be done without the context being protected. We come + * here when the context has become unreacheable by other tasks. + * + * We may still have active monitoring at this point and we may + * end up in pfm_overflow_handler(). However, fasync_helper() + * operates with interrupts disabled and it cleans up the + * queue. If the PMU handler is called prior to entering + * fasync_helper() then it will send a signal. If it is + * invoked after, it will find an empty queue and no + * signal will be sent. In both case, we are safe + */ + if (filp->f_flags & FASYNC) { + DPRINT(("cleaning up async_queue=%p\n", ctx->ctx_async_queue)); + pfm_do_fasync (-1, filp, ctx, 0); + } + + PROTECT_CTX(ctx, flags); + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + task = PFM_CTX_TASK(ctx); + regs = task_pt_regs(task); + + DPRINT(("ctx_state=%d is_current=%d\n", + state, + task == current ? 1 : 0)); + + /* + * if state == UNLOADED, then task is NULL + */ + + /* + * we must stop and unload because we are losing access to the context. + */ + if (task == current) { +#ifdef CONFIG_SMP + /* + * the task IS the owner but it migrated to another CPU: that's bad + * but we must handle this cleanly. Unfortunately, the kernel does + * not provide a mechanism to block migration (while the context is loaded). + * + * We need to release the resource on the ORIGINAL cpu. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + /* + * keep context protected but unmask interrupt for IPI + */ + local_irq_restore(flags); + + pfm_syswide_cleanup_other_cpu(ctx); + + /* + * restore interrupt masking + */ + local_irq_save(flags); + + /* + * context is unloaded at this point + */ + } else +#endif /* CONFIG_SMP */ + { + + DPRINT(("forcing unload\n")); + /* + * stop and unload, returning with state UNLOADED + * and session unreserved. + */ + pfm_context_unload(ctx, NULL, 0, regs); + + DPRINT(("ctx_state=%d\n", ctx->ctx_state)); + } + } + + /* + * remove virtual mapping, if any, for the calling task. + * cannot reset ctx field until last user is calling close(). + * + * ctx_smpl_vaddr must never be cleared because it is needed + * by every task with access to the context + * + * When called from do_exit(), the mm context is gone already, therefore + * mm is NULL, i.e., the VMA is already gone and we do not have to + * do anything here + */ + if (ctx->ctx_smpl_vaddr && current->mm) { + smpl_buf_vaddr = ctx->ctx_smpl_vaddr; + smpl_buf_size = ctx->ctx_smpl_size; + } + + UNPROTECT_CTX(ctx, flags); + + /* + * if there was a mapping, then we systematically remove it + * at this point. Cannot be done inside critical section + * because some VM function reenables interrupts. + * + */ + if (smpl_buf_vaddr) pfm_remove_smpl_mapping(current, smpl_buf_vaddr, smpl_buf_size); + + return 0; +} +/* + * called either on explicit close() or from exit_files(). + * Only the LAST user of the file gets to this point, i.e., it is + * called only ONCE. + * + * IMPORTANT: we get called ONLY when the refcnt on the file gets to zero + * (fput()),i.e, last task to access the file. Nobody else can access the + * file at this point. + * + * When called from exit_files(), the VMA has been freed because exit_mm() + * is executed before exit_files(). + * + * When called from exit_files(), the current task is not yet ZOMBIE but we + * flush the PMU state to the context. + */ +static int +pfm_close(struct inode *inode, struct file *filp) +{ + pfm_context_t *ctx; + struct task_struct *task; + struct pt_regs *regs; + DECLARE_WAITQUEUE(wait, current); + unsigned long flags; + unsigned long smpl_buf_size = 0UL; + void *smpl_buf_addr = NULL; + int free_possible = 1; + int state, is_system; + + DPRINT(("pfm_close called private=%p\n", filp->private_data)); + + if (PFM_IS_FILE(filp) == 0) { + DPRINT(("bad magic\n")); + return -EBADF; + } + + ctx = (pfm_context_t *)filp->private_data; + if (ctx == NULL) { + printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", current->pid); + return -EBADF; + } + + PROTECT_CTX(ctx, flags); + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + task = PFM_CTX_TASK(ctx); + regs = task_pt_regs(task); + + DPRINT(("ctx_state=%d is_current=%d\n", + state, + task == current ? 1 : 0)); + + /* + * if task == current, then pfm_flush() unloaded the context + */ + if (state == PFM_CTX_UNLOADED) goto doit; + + /* + * context is loaded/masked and task != current, we need to + * either force an unload or go zombie + */ + + /* + * The task is currently blocked or will block after an overflow. + * we must force it to wakeup to get out of the + * MASKED state and transition to the unloaded state by itself. + * + * This situation is only possible for per-task mode + */ + if (state == PFM_CTX_MASKED && CTX_OVFL_NOBLOCK(ctx) == 0) { + + /* + * set a "partial" zombie state to be checked + * upon return from down() in pfm_handle_work(). + * + * We cannot use the ZOMBIE state, because it is checked + * by pfm_load_regs() which is called upon wakeup from down(). + * In such case, it would free the context and then we would + * return to pfm_handle_work() which would access the + * stale context. Instead, we set a flag invisible to pfm_load_regs() + * but visible to pfm_handle_work(). + * + * For some window of time, we have a zombie context with + * ctx_state = MASKED and not ZOMBIE + */ + ctx->ctx_fl_going_zombie = 1; + + /* + * force task to wake up from MASKED state + */ + complete(&ctx->ctx_restart_done); + + DPRINT(("waking up ctx_state=%d\n", state)); + + /* + * put ourself to sleep waiting for the other + * task to report completion + * + * the context is protected by mutex, therefore there + * is no risk of being notified of completion before + * begin actually on the waitq. + */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&ctx->ctx_zombieq, &wait); + + UNPROTECT_CTX(ctx, flags); + + /* + * XXX: check for signals : + * - ok for explicit close + * - not ok when coming from exit_files() + */ + schedule(); + + + PROTECT_CTX(ctx, flags); + + + remove_wait_queue(&ctx->ctx_zombieq, &wait); + set_current_state(TASK_RUNNING); + + /* + * context is unloaded at this point + */ + DPRINT(("after zombie wakeup ctx_state=%d for\n", state)); + } + else if (task != current) { +#ifdef CONFIG_SMP + /* + * switch context to zombie state + */ + ctx->ctx_state = PFM_CTX_ZOMBIE; + + DPRINT(("zombie ctx for [%d]\n", task->pid)); + /* + * cannot free the context on the spot. deferred until + * the task notices the ZOMBIE state + */ + free_possible = 0; +#else + pfm_context_unload(ctx, NULL, 0, regs); +#endif + } + +doit: + /* reload state, may have changed during opening of critical section */ + state = ctx->ctx_state; + + /* + * the context is still attached to a task (possibly current) + * we cannot destroy it right now + */ + + /* + * we must free the sampling buffer right here because + * we cannot rely on it being cleaned up later by the + * monitored task. It is not possible to free vmalloc'ed + * memory in pfm_load_regs(). Instead, we remove the buffer + * now. should there be subsequent PMU overflow originally + * meant for sampling, the will be converted to spurious + * and that's fine because the monitoring tools is gone anyway. + */ + if (ctx->ctx_smpl_hdr) { + smpl_buf_addr = ctx->ctx_smpl_hdr; + smpl_buf_size = ctx->ctx_smpl_size; + /* no more sampling */ + ctx->ctx_smpl_hdr = NULL; + ctx->ctx_fl_is_sampling = 0; + } + + DPRINT(("ctx_state=%d free_possible=%d addr=%p size=%lu\n", + state, + free_possible, + smpl_buf_addr, + smpl_buf_size)); + + if (smpl_buf_addr) pfm_exit_smpl_buffer(ctx->ctx_buf_fmt); + + /* + * UNLOADED that the session has already been unreserved. + */ + if (state == PFM_CTX_ZOMBIE) { + pfm_unreserve_session(ctx, ctx->ctx_fl_system , ctx->ctx_cpu); + } + + /* + * disconnect file descriptor from context must be done + * before we unlock. + */ + filp->private_data = NULL; + + /* + * if we free on the spot, the context is now completely unreacheable + * from the callers side. The monitored task side is also cut, so we + * can freely cut. + * + * If we have a deferred free, only the caller side is disconnected. + */ + UNPROTECT_CTX(ctx, flags); + + /* + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (smpl_buf_addr) pfm_rvfree(smpl_buf_addr, smpl_buf_size); + + /* + * return the memory used by the context + */ + if (free_possible) pfm_context_free(ctx); + + return 0; +} + +static int +pfm_no_open(struct inode *irrelevant, struct file *dontcare) +{ + DPRINT(("pfm_no_open called\n")); + return -ENXIO; +} + + + +static struct file_operations pfm_file_ops = { + .llseek = no_llseek, + .read = pfm_read, + .write = pfm_write, + .poll = pfm_poll, + .ioctl = pfm_ioctl, + .open = pfm_no_open, /* special open code to disallow open via /proc */ + .fasync = pfm_fasync, + .release = pfm_close, + .flush = pfm_flush +}; + +static int +pfmfs_delete_dentry(struct dentry *dentry) +{ + return 1; +} + +static struct dentry_operations pfmfs_dentry_operations = { + .d_delete = pfmfs_delete_dentry, +}; + + +static int +pfm_alloc_fd(struct file **cfile) +{ + int fd, ret = 0; + struct file *file = NULL; + struct inode * inode; + char name[32]; + struct qstr this; + + fd = get_unused_fd(); + if (fd < 0) return -ENFILE; + + ret = -ENFILE; + + file = get_empty_filp(); + if (!file) goto out; + + /* + * allocate a new inode + */ + inode = new_inode(pfmfs_mnt->mnt_sb); + if (!inode) goto out; + + DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode)); + + inode->i_mode = S_IFCHR|S_IRUGO; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + + sprintf(name, "[%lu]", inode->i_ino); + this.name = name; + this.len = strlen(name); + this.hash = inode->i_ino; + + ret = -ENOMEM; + + /* + * allocate a new dcache entry + */ + file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this); + if (!file->f_dentry) goto out; + + file->f_dentry->d_op = &pfmfs_dentry_operations; + + d_add(file->f_dentry, inode); + file->f_vfsmnt = mntget(pfmfs_mnt); + file->f_mapping = inode->i_mapping; + + file->f_op = &pfm_file_ops; + file->f_mode = FMODE_READ; + file->f_flags = O_RDONLY; + file->f_pos = 0; + + /* + * may have to delay until context is attached? + */ + fd_install(fd, file); + + /* + * the file structure we will use + */ + *cfile = file; + + return fd; +out: + if (file) put_filp(file); + put_unused_fd(fd); + return ret; +} + +static void +pfm_free_fd(int fd, struct file *file) +{ + struct files_struct *files = current->files; + struct fdtable *fdt; + + /* + * there ie no fd_uninstall(), so we do it here + */ + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + rcu_assign_pointer(fdt->fd[fd], NULL); + spin_unlock(&files->file_lock); + + if (file) + put_filp(file); + put_unused_fd(fd); +} + +static int +pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) +{ + DPRINT(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); + + while (size > 0) { + unsigned long pfn = ia64_tpa(buf) >> PAGE_SHIFT; + + + if (remap_pfn_range(vma, addr, pfn, PAGE_SIZE, PAGE_READONLY)) + return -ENOMEM; + + addr += PAGE_SIZE; + buf += PAGE_SIZE; + size -= PAGE_SIZE; + } + return 0; +} + +/* + * allocate a sampling buffer and remaps it into the user address space of the task + */ +static int +pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma = NULL; + unsigned long size; + void *smpl_buf; + + + /* + * the fixed header + requested size and align to page boundary + */ + size = PAGE_ALIGN(rsize); + + DPRINT(("sampling buffer rsize=%lu size=%lu bytes\n", rsize, size)); + + /* + * check requested size to avoid Denial-of-service attacks + * XXX: may have to refine this test + * Check against address space limit. + * + * if ((mm->total_vm << PAGE_SHIFT) + len> task->rlim[RLIMIT_AS].rlim_cur) + * return -ENOMEM; + */ + if (size > task->signal->rlim[RLIMIT_MEMLOCK].rlim_cur) + return -ENOMEM; + + /* + * We do the easy to undo allocations first. + * + * pfm_rvmalloc(), clears the buffer, so there is no leak + */ + smpl_buf = pfm_rvmalloc(size); + if (smpl_buf == NULL) { + DPRINT(("Can't allocate sampling buffer\n")); + return -ENOMEM; + } + + DPRINT(("smpl_buf @%p\n", smpl_buf)); + + /* allocate vma */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (!vma) { + DPRINT(("Cannot allocate vma\n")); + goto error_kmem; + } + memset(vma, 0, sizeof(*vma)); + + /* + * partially initialize the vma for the sampling buffer + */ + vma->vm_mm = mm; + vma->vm_flags = VM_READ| VM_MAYREAD |VM_RESERVED; + vma->vm_page_prot = PAGE_READONLY; /* XXX may need to change */ + + /* + * Now we have everything we need and we can initialize + * and connect all the data structures + */ + + ctx->ctx_smpl_hdr = smpl_buf; + ctx->ctx_smpl_size = size; /* aligned size */ + + /* + * Let's do the difficult operations next. + * + * now we atomically find some area in the address space and + * remap the buffer in it. + */ + down_write(&task->mm->mmap_sem); + + /* find some free area in address space, must have mmap sem held */ + vma->vm_start = pfm_get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE|MAP_ANONYMOUS, 0); + if (vma->vm_start == 0UL) { + DPRINT(("Cannot find unmapped area for size %ld\n", size)); + up_write(&task->mm->mmap_sem); + goto error; + } + vma->vm_end = vma->vm_start + size; + vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT; + + DPRINT(("aligned size=%ld, hdr=%p mapped @0x%lx\n", size, ctx->ctx_smpl_hdr, vma->vm_start)); + + /* can only be applied to current task, need to have the mm semaphore held when called */ + if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) { + DPRINT(("Can't remap buffer\n")); + up_write(&task->mm->mmap_sem); + goto error; + } + + /* + * now insert the vma in the vm list for the process, must be + * done with mmap lock held + */ + insert_vm_struct(mm, vma); + + mm->total_vm += size >> PAGE_SHIFT; + vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, + vma_pages(vma)); + up_write(&task->mm->mmap_sem); + + /* + * keep track of user level virtual address + */ + ctx->ctx_smpl_vaddr = (void *)vma->vm_start; + *(unsigned long *)user_vaddr = vma->vm_start; + + return 0; + +error: + kmem_cache_free(vm_area_cachep, vma); +error_kmem: + pfm_rvfree(smpl_buf, size); + + return -ENOMEM; +} + +/* + * XXX: do something better here + */ +static int +pfm_bad_permissions(struct task_struct *task) +{ + /* inspired by ptrace_attach() */ + DPRINT(("cur: uid=%d gid=%d task: euid=%d suid=%d uid=%d egid=%d sgid=%d\n", + current->uid, + current->gid, + task->euid, + task->suid, + task->uid, + task->egid, + task->sgid)); + + return ((current->uid != task->euid) + || (current->uid != task->suid) + || (current->uid != task->uid) + || (current->gid != task->egid) + || (current->gid != task->sgid) + || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE); +} + +static int +pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) +{ + int ctx_flags; + + /* valid signal */ + + ctx_flags = pfx->ctx_flags; + + if (ctx_flags & PFM_FL_SYSTEM_WIDE) { + + /* + * cannot block in this mode + */ + if (ctx_flags & PFM_FL_NOTIFY_BLOCK) { + DPRINT(("cannot use blocking mode when in system wide monitoring\n")); + return -EINVAL; + } + } else { + } + /* probably more to add here */ + + return 0; +} + +static int +pfm_setup_buffer_fmt(struct task_struct *task, pfm_context_t *ctx, unsigned int ctx_flags, + unsigned int cpu, pfarg_context_t *arg) +{ + pfm_buffer_fmt_t *fmt = NULL; + unsigned long size = 0UL; + void *uaddr = NULL; + void *fmt_arg = NULL; + int ret = 0; +#define PFM_CTXARG_BUF_ARG(a) (pfm_buffer_fmt_t *)(a+1) + + /* invoke and lock buffer format, if found */ + fmt = pfm_find_buffer_fmt(arg->ctx_smpl_buf_id); + if (fmt == NULL) { + DPRINT(("[%d] cannot find buffer format\n", task->pid)); + return -EINVAL; + } + + /* + * buffer argument MUST be contiguous to pfarg_context_t + */ + if (fmt->fmt_arg_size) fmt_arg = PFM_CTXARG_BUF_ARG(arg); + + ret = pfm_buf_fmt_validate(fmt, task, ctx_flags, cpu, fmt_arg); + + DPRINT(("[%d] after validate(0x%x,%d,%p)=%d\n", task->pid, ctx_flags, cpu, fmt_arg, ret)); + + if (ret) goto error; + + /* link buffer format and context */ + ctx->ctx_buf_fmt = fmt; + + /* + * check if buffer format wants to use perfmon buffer allocation/mapping service + */ + ret = pfm_buf_fmt_getsize(fmt, task, ctx_flags, cpu, fmt_arg, &size); + if (ret) goto error; + + if (size) { + /* + * buffer is always remapped into the caller's address space + */ + ret = pfm_smpl_buffer_alloc(current, ctx, size, &uaddr); + if (ret) goto error; + + /* keep track of user address of buffer */ + arg->ctx_smpl_vaddr = uaddr; + } + ret = pfm_buf_fmt_init(fmt, task, ctx->ctx_smpl_hdr, ctx_flags, cpu, fmt_arg); + +error: + return ret; +} + +static void +pfm_reset_pmu_state(pfm_context_t *ctx) +{ + int i; + + /* + * install reset values for PMC. + */ + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + ctx->ctx_pmcs[i] = PMC_DFL_VAL(i); + DPRINT(("pmc[%d]=0x%lx\n", i, ctx->ctx_pmcs[i])); + } + /* + * PMD registers are set to 0UL when the context in memset() + */ + + /* + * On context switched restore, we must restore ALL pmc and ALL pmd even + * when they are not actively used by the task. In UP, the incoming process + * may otherwise pick up left over PMC, PMD state from the previous process. + * As opposed to PMD, stale PMC can cause harm to the incoming + * process because they may change what is being measured. + * Therefore, we must systematically reinstall the entire + * PMC state. In SMP, the same thing is possible on the + * same CPU but also on between 2 CPUs. + * + * The problem with PMD is information leaking especially + * to user level when psr.sp=0 + * + * There is unfortunately no easy way to avoid this problem + * on either UP or SMP. This definitively slows down the + * pfm_load_regs() function. + */ + + /* + * bitmask of all PMCs accessible to this context + * + * PMC0 is treated differently. + */ + ctx->ctx_all_pmcs[0] = pmu_conf->impl_pmcs[0] & ~0x1; + + /* + * bitmask of all PMDs that are accesible to this context + */ + ctx->ctx_all_pmds[0] = pmu_conf->impl_pmds[0]; + + DPRINT(("<%d> all_pmcs=0x%lx all_pmds=0x%lx\n", ctx->ctx_fd, ctx->ctx_all_pmcs[0],ctx->ctx_all_pmds[0])); + + /* + * useful in case of re-enable after disable + */ + ctx->ctx_used_ibrs[0] = 0UL; + ctx->ctx_used_dbrs[0] = 0UL; +} + +static int +pfm_ctx_getsize(void *arg, size_t *sz) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + pfm_buffer_fmt_t *fmt; + + *sz = 0; + + if (!pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) return 0; + + fmt = pfm_find_buffer_fmt(req->ctx_smpl_buf_id); + if (fmt == NULL) { + DPRINT(("cannot find buffer format\n")); + return -EINVAL; + } + /* get just enough to copy in user parameters */ + *sz = fmt->fmt_arg_size; + DPRINT(("arg_size=%lu\n", *sz)); + + return 0; +} + + + +/* + * cannot attach if : + * - kernel task + * - task not owned by caller + * - task incompatible with context mode + */ +static int +pfm_task_incompatible(pfm_context_t *ctx, struct task_struct *task) +{ + /* + * no kernel task or task not owner by caller + */ + if (task->mm == NULL) { + DPRINT(("task [%d] has not memory context (kernel thread)\n", task->pid)); + return -EPERM; + } + if (pfm_bad_permissions(task)) { + DPRINT(("no permission to attach to [%d]\n", task->pid)); + return -EPERM; + } + /* + * cannot block in self-monitoring mode + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && task == current) { + DPRINT(("cannot load a blocking context on self for [%d]\n", task->pid)); + return -EINVAL; + } + + if (task->exit_state == EXIT_ZOMBIE) { + DPRINT(("cannot attach to zombie task [%d]\n", task->pid)); + return -EBUSY; + } + + /* + * always ok for self + */ + if (task == current) return 0; + + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { + DPRINT(("cannot attach to non-stopped task [%d] state=%ld\n", task->pid, task->state)); + return -EBUSY; + } + /* + * make sure the task is off any CPU + */ + wait_task_inactive(task); + + /* more to come... */ + + return 0; +} + +static int +pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task) +{ + struct task_struct *p = current; + int ret; + + /* XXX: need to add more checks here */ + if (pid < 2) return -EPERM; + + if (pid != current->pid) { + + read_lock(&tasklist_lock); + + p = find_task_by_pid(pid); + + /* make sure task cannot go away while we operate on it */ + if (p) get_task_struct(p); + + read_unlock(&tasklist_lock); + + if (p == NULL) return -ESRCH; + } + + ret = pfm_task_incompatible(ctx, p); + if (ret == 0) { + *task = p; + } else if (p != current) { + pfm_put_task(p); + } + return ret; +} + + + +static int +pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_context_t *req = (pfarg_context_t *)arg; + struct file *filp; + int ctx_flags; + int ret; + + /* let's check the arguments first */ + ret = pfarg_is_sane(current, req); + if (ret < 0) return ret; + + ctx_flags = req->ctx_flags; + + ret = -ENOMEM; + + ctx = pfm_context_alloc(); + if (!ctx) goto error; + + ret = pfm_alloc_fd(&filp); + if (ret < 0) goto error_file; + + req->ctx_fd = ctx->ctx_fd = ret; + + /* + * attach context to file + */ + filp->private_data = ctx; + + /* + * does the user want to sample? + */ + if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) { + ret = pfm_setup_buffer_fmt(current, ctx, ctx_flags, 0, req); + if (ret) goto buffer_error; + } + + /* + * init context protection lock + */ + spin_lock_init(&ctx->ctx_lock); + + /* + * context is unloaded + */ + ctx->ctx_state = PFM_CTX_UNLOADED; + + /* + * initialization of context's flags + */ + ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0; + ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0; + ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */ + ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0; + /* + * will move to set properties + * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; + */ + + /* + * init restart semaphore to locked + */ + init_completion(&ctx->ctx_restart_done); + + /* + * activation is used in SMP only + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * initialize notification message queue + */ + ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; + init_waitqueue_head(&ctx->ctx_msgq_wait); + init_waitqueue_head(&ctx->ctx_zombieq); + + DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n", + ctx, + ctx_flags, + ctx->ctx_fl_system, + ctx->ctx_fl_block, + ctx->ctx_fl_excl_idle, + ctx->ctx_fl_no_msg, + ctx->ctx_fd)); + + /* + * initialize soft PMU state + */ + pfm_reset_pmu_state(ctx); + + return 0; + +buffer_error: + pfm_free_fd(ctx->ctx_fd, filp); + + if (ctx->ctx_buf_fmt) { + pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); + } +error_file: + pfm_context_free(ctx); + +error: + return ret; +} + +static inline unsigned long +pfm_new_counter_value (pfm_counter_t *reg, int is_long_reset) +{ + unsigned long val = is_long_reset ? reg->long_reset : reg->short_reset; + unsigned long new_seed, old_seed = reg->seed, mask = reg->mask; + extern unsigned long carta_random32 (unsigned long seed); + + if (reg->flags & PFM_REGFL_RANDOM) { + new_seed = carta_random32(old_seed); + val -= (old_seed & mask); /* counter values are negative numbers! */ + if ((mask >> 32) != 0) + /* construct a full 64-bit random value: */ + new_seed |= carta_random32(old_seed >> 32) << 32; + reg->seed = new_seed; + } + reg->lval = val; + return val; +} + +static void +pfm_reset_regs_masked(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i; + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + + if ((mask & 0x1UL) == 0UL) continue; + + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val)); + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + ctx->ctx_pmds[i].val = val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } +} + +static void +pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset) +{ + unsigned long mask = ovfl_regs[0]; + unsigned long reset_others = 0UL; + unsigned long val; + int i; + + DPRINT_ovfl(("ovfl_regs=0x%lx is_long_reset=%d\n", ovfl_regs[0], is_long_reset)); + + if (ctx->ctx_state == PFM_CTX_MASKED) { + pfm_reset_regs_masked(ctx, ovfl_regs, is_long_reset); + return; + } + + /* + * now restore reset value on sampling overflowed counters + */ + mask >>= PMU_FIRST_COUNTER; + for(i = PMU_FIRST_COUNTER; mask; i++, mask >>= 1) { + + if ((mask & 0x1UL) == 0UL) continue; + + val = pfm_new_counter_value(ctx->ctx_pmds+ i, is_long_reset); + reset_others |= ctx->ctx_pmds[i].reset_pmds[0]; + + DPRINT_ovfl((" %s reset ctx_pmds[%d]=%lx\n", is_long_reset ? "long" : "short", i, val)); + + pfm_write_soft_counter(ctx, i, val); + } + + /* + * Now take care of resetting the other registers + */ + for(i = 0; reset_others; i++, reset_others >>= 1) { + + if ((reset_others & 0x1) == 0) continue; + + val = pfm_new_counter_value(ctx->ctx_pmds + i, is_long_reset); + + if (PMD_IS_COUNTING(i)) { + pfm_write_soft_counter(ctx, i, val); + } else { + ia64_set_pmd(i, val); + } + DPRINT_ovfl(("%s reset_others pmd[%d]=%lx\n", + is_long_reset ? "long" : "short", i, val)); + } + ia64_srlz_d(); +} + +static int +pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value, pmc_pm; + unsigned long smpl_pmds, reset_pmds, impl_pmds; + unsigned int cnum, reg_flags, flags, pmc_type; + int i, can_access_pmu = 0, is_loaded, is_system, expert_mode; + int is_monitor, is_counting, state; + int ret = -EINVAL; + pfm_reg_check_t wr_func; +#define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z)) + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + task = ctx->ctx_task; + impl_pmds = pmu_conf->impl_pmds[0]; + + if (state == PFM_CTX_ZOMBIE) return -EINVAL; + + if (is_loaded) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + } + expert_mode = pfm_sysctl.expert_mode; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + reg_flags = req->reg_flags; + value = req->reg_value; + smpl_pmds = req->reg_smpl_pmds[0]; + reset_pmds = req->reg_reset_pmds[0]; + flags = 0; + + + if (cnum >= PMU_MAX_PMCS) { + DPRINT(("pmc%u is invalid\n", cnum)); + goto error; + } + + pmc_type = pmu_conf->pmc_desc[cnum].type; + pmc_pm = (value >> pmu_conf->pmc_desc[cnum].pm_pos) & 0x1; + is_counting = (pmc_type & PFM_REG_COUNTING) == PFM_REG_COUNTING ? 1 : 0; + is_monitor = (pmc_type & PFM_REG_MONITOR) == PFM_REG_MONITOR ? 1 : 0; + + /* + * we reject all non implemented PMC as well + * as attempts to modify PMC[0-3] which are used + * as status registers by the PMU + */ + if ((pmc_type & PFM_REG_IMPL) == 0 || (pmc_type & PFM_REG_CONTROL) == PFM_REG_CONTROL) { + DPRINT(("pmc%u is unimplemented or no-access pmc_type=%x\n", cnum, pmc_type)); + goto error; + } + wr_func = pmu_conf->pmc_desc[cnum].write_check; + /* + * If the PMC is a monitor, then if the value is not the default: + * - system-wide session: PMCx.pm=1 (privileged monitor) + * - per-task : PMCx.pm=0 (user monitor) + */ + if (is_monitor && value != PMC_DFL_VAL(cnum) && is_system ^ pmc_pm) { + DPRINT(("pmc%u pmc_pm=%lu is_system=%d\n", + cnum, + pmc_pm, + is_system)); + goto error; + } + + if (is_counting) { + /* + * enforce generation of overflow interrupt. Necessary on all + * CPUs. + */ + value |= 1 << PMU_PMC_OI; + + if (reg_flags & PFM_REGFL_OVFL_NOTIFY) { + flags |= PFM_REGFL_OVFL_NOTIFY; + } + + if (reg_flags & PFM_REGFL_RANDOM) flags |= PFM_REGFL_RANDOM; + + /* verify validity of smpl_pmds */ + if ((smpl_pmds & impl_pmds) != smpl_pmds) { + DPRINT(("invalid smpl_pmds 0x%lx for pmc%u\n", smpl_pmds, cnum)); + goto error; + } + + /* verify validity of reset_pmds */ + if ((reset_pmds & impl_pmds) != reset_pmds) { + DPRINT(("invalid reset_pmds 0x%lx for pmc%u\n", reset_pmds, cnum)); + goto error; + } + } else { + if (reg_flags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) { + DPRINT(("cannot set ovfl_notify or random on pmc%u\n", cnum)); + goto error; + } + /* eventid on non-counting monitors are ignored */ + } + + /* + * execute write checker, if any + */ + if (likely(expert_mode == 0 && wr_func)) { + ret = (*wr_func)(task, ctx, cnum, &value, regs); + if (ret) goto error; + ret = -EINVAL; + } + + /* + * no error on this register + */ + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + /* + * Now we commit the changes to the software state + */ + + /* + * update overflow information + */ + if (is_counting) { + /* + * full flag update each time a register is programmed + */ + ctx->ctx_pmds[cnum].flags = flags; + + ctx->ctx_pmds[cnum].reset_pmds[0] = reset_pmds; + ctx->ctx_pmds[cnum].smpl_pmds[0] = smpl_pmds; + ctx->ctx_pmds[cnum].eventid = req->reg_smpl_eventid; + + /* + * Mark all PMDS to be accessed as used. + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + * + * We do not update the used_monitors mask, because + * if we have not programmed them, then will be in + * a quiescent state, therefore we will not need to + * mask/restore then when context is MASKED. + */ + CTX_USED_PMD(ctx, reset_pmds); + CTX_USED_PMD(ctx, smpl_pmds); + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (state == PFM_CTX_MASKED) ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } + /* + * Needed in case the user does not initialize the equivalent + * PMD. Clearing is done indirectly via pfm_reset_pmu_state() so there is no + * possible leak here. + */ + CTX_USED_PMD(ctx, pmu_conf->pmc_desc[cnum].dep_pmd[0]); + + /* + * keep track of the monitor PMC that we are using. + * we save the value of the pmc in ctx_pmcs[] and if + * the monitoring is not stopped for the context we also + * place it in the saved state area so that it will be + * picked up later by the context switch code. + * + * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs(). + * + * The value in thread->pmcs[] may be modified on overflow, i.e., when + * monitoring needs to be stopped. + */ + if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum); + + /* + * update context state + */ + ctx->ctx_pmcs[cnum] = value; + + if (is_loaded) { + /* + * write thread state + */ + if (is_system == 0) thread->pmcs[cnum] = value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmc(cnum, value); + } +#ifdef CONFIG_SMP + else { + /* + * per-task SMP only here + * + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmcs[0] |= 1UL << cnum; + } +#endif + } + + DPRINT(("pmc[%u]=0x%lx ld=%d apmu=%d flags=0x%x all_pmcs=0x%lx used_pmds=0x%lx eventid=%ld smpl_pmds=0x%lx reset_pmds=0x%lx reloads_pmcs=0x%lx used_monitors=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + flags, + ctx->ctx_all_pmcs[0], + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].eventid, + smpl_pmds, + reset_pmds, + ctx->ctx_reload_pmcs[0], + ctx->ctx_used_monitors[0], + ctx->ctx_ovfl_regs[0])); + } + + /* + * make sure the changes are visible + */ + if (can_access_pmu) ia64_srlz_d(); + + return 0; +error: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +static int +pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned long value, hw_value, ovfl_mask; + unsigned int cnum; + int i, can_access_pmu = 0, state; + int is_counting, is_loaded, is_system, expert_mode; + int ret = -EINVAL; + pfm_reg_check_t wr_func; + + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + ovfl_mask = pmu_conf->ovfl_val; + task = ctx->ctx_task; + + if (unlikely(state == PFM_CTX_ZOMBIE)) return -EINVAL; + + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (likely(is_loaded)) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + } + expert_mode = pfm_sysctl.expert_mode; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + value = req->reg_value; + + if (!PMD_IS_IMPL(cnum)) { + DPRINT(("pmd[%u] is unimplemented or invalid\n", cnum)); + goto abort_mission; + } + is_counting = PMD_IS_COUNTING(cnum); + wr_func = pmu_conf->pmd_desc[cnum].write_check; + + /* + * execute write checker, if any + */ + if (unlikely(expert_mode == 0 && wr_func)) { + unsigned long v = value; + + ret = (*wr_func)(task, ctx, cnum, &v, regs); + if (ret) goto abort_mission; + + value = v; + ret = -EINVAL; + } + + /* + * no error on this register + */ + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + /* + * now commit changes to software state + */ + hw_value = value; + + /* + * update virtualized (64bits) counter + */ + if (is_counting) { + /* + * write context state + */ + ctx->ctx_pmds[cnum].lval = value; + + /* + * when context is load we use the split value + */ + if (is_loaded) { + hw_value = value & ovfl_mask; + value = value & ~ovfl_mask; + } + } + /* + * update reset values (not just for counters) + */ + ctx->ctx_pmds[cnum].long_reset = req->reg_long_reset; + ctx->ctx_pmds[cnum].short_reset = req->reg_short_reset; + + /* + * update randomization parameters (not just for counters) + */ + ctx->ctx_pmds[cnum].seed = req->reg_random_seed; + ctx->ctx_pmds[cnum].mask = req->reg_random_mask; + + /* + * update context value + */ + ctx->ctx_pmds[cnum].val = value; + + /* + * Keep track of what we use + * + * We do not keep track of PMC because we have to + * systematically restore ALL of them. + */ + CTX_USED_PMD(ctx, PMD_PMD_DEP(cnum)); + + /* + * mark this PMD register used as well + */ + CTX_USED_PMD(ctx, RDEP(cnum)); + + /* + * make sure we do not try to reset on + * restart because we have established new values + */ + if (is_counting && state == PFM_CTX_MASKED) { + ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; + } + + if (is_loaded) { + /* + * write thread state + */ + if (is_system == 0) thread->pmds[cnum] = hw_value; + + /* + * write hardware register if we can + */ + if (can_access_pmu) { + ia64_set_pmd(cnum, hw_value); + } else { +#ifdef CONFIG_SMP + /* + * we are guaranteed that the task is not running on the other CPU, + * we indicate that this PMD will need to be reloaded if the task + * is rescheduled on the CPU it ran last on. + */ + ctx->ctx_reload_pmds[0] |= 1UL << cnum; +#endif + } + } + + DPRINT(("pmd[%u]=0x%lx ld=%d apmu=%d, hw_value=0x%lx ctx_pmd=0x%lx short_reset=0x%lx " + "long_reset=0x%lx notify=%c seed=0x%lx mask=0x%lx used_pmds=0x%lx reset_pmds=0x%lx reload_pmds=0x%lx all_pmds=0x%lx ovfl_regs=0x%lx\n", + cnum, + value, + is_loaded, + can_access_pmu, + hw_value, + ctx->ctx_pmds[cnum].val, + ctx->ctx_pmds[cnum].short_reset, + ctx->ctx_pmds[cnum].long_reset, + PMC_OVFL_NOTIFY(ctx, cnum) ? 'Y':'N', + ctx->ctx_pmds[cnum].seed, + ctx->ctx_pmds[cnum].mask, + ctx->ctx_used_pmds[0], + ctx->ctx_pmds[cnum].reset_pmds[0], + ctx->ctx_reload_pmds[0], + ctx->ctx_all_pmds[0], + ctx->ctx_ovfl_regs[0])); + } + + /* + * make changes visible + */ + if (can_access_pmu) ia64_srlz_d(); + + return 0; + +abort_mission: + /* + * for now, we have only one possibility for error + */ + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +/* + * By the way of PROTECT_CONTEXT(), interrupts are masked while we are in this function. + * Therefore we know, we do not have to worry about the PMU overflow interrupt. If an + * interrupt is delivered during the call, it will be kept pending until we leave, making + * it appears as if it had been generated at the UNPROTECT_CONTEXT(). At least we are + * guaranteed to return consistent data to the user, it may simply be old. It is not + * trivial to treat the overflow while inside the call because you may end up in + * some module sampling buffer code causing deadlocks. + */ +static int +pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + unsigned long val = 0UL, lval, ovfl_mask, sval; + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned int cnum, reg_flags = 0; + int i, can_access_pmu = 0, state; + int is_loaded, is_system, is_counting, expert_mode; + int ret = -EINVAL; + pfm_reg_check_t rd_func; + + /* + * access is possible when loaded only for + * self-monitoring tasks or in UP mode + */ + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + ovfl_mask = pmu_conf->ovfl_val; + task = ctx->ctx_task; + + if (state == PFM_CTX_ZOMBIE) return -EINVAL; + + if (likely(is_loaded)) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + /* + * this can be true when not self-monitoring only in UP + */ + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + + if (can_access_pmu) ia64_srlz_d(); + } + expert_mode = pfm_sysctl.expert_mode; + + DPRINT(("ld=%d apmu=%d ctx_state=%d\n", + is_loaded, + can_access_pmu, + state)); + + /* + * on both UP and SMP, we can only read the PMD from the hardware register when + * the task is the owner of the local PMU. + */ + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + reg_flags = req->reg_flags; + + if (unlikely(!PMD_IS_IMPL(cnum))) goto error; + /* + * we can only read the register that we use. That includes + * the one we explicitely initialize AND the one we want included + * in the sampling buffer (smpl_regs). + * + * Having this restriction allows optimization in the ctxsw routine + * without compromising security (leaks) + */ + if (unlikely(!CTX_IS_USED_PMD(ctx, cnum))) goto error; + + sval = ctx->ctx_pmds[cnum].val; + lval = ctx->ctx_pmds[cnum].lval; + is_counting = PMD_IS_COUNTING(cnum); + + /* + * If the task is not the current one, then we check if the + * PMU state is still in the local live register due to lazy ctxsw. + * If true, then we read directly from the registers. + */ + if (can_access_pmu){ + val = ia64_get_pmd(cnum); + } else { + /* + * context has been saved + * if context is zombie, then task does not exist anymore. + * In this case, we use the full value saved in the context (pfm_flush_regs()). + */ + val = is_loaded ? thread->pmds[cnum] : 0UL; + } + rd_func = pmu_conf->pmd_desc[cnum].read_check; + + if (is_counting) { + /* + * XXX: need to check for overflow when loaded + */ + val &= ovfl_mask; + val += sval; + } + + /* + * execute read checker, if any + */ + if (unlikely(expert_mode == 0 && rd_func)) { + unsigned long v = val; + ret = (*rd_func)(ctx->ctx_task, ctx, cnum, &v, regs); + if (ret) goto error; + val = v; + ret = -EINVAL; + } + + PFM_REG_RETFLAG_SET(reg_flags, 0); + + DPRINT(("pmd[%u]=0x%lx\n", cnum, val)); + + /* + * update register return value, abort all if problem during copy. + * we only modify the reg_flags field. no check mode is fine because + * access has been verified upfront in sys_perfmonctl(). + */ + req->reg_value = val; + req->reg_flags = reg_flags; + req->reg_last_reset_val = lval; + } + + return 0; + +error: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +int +pfm_mod_write_pmcs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_write_pmcs(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_write_pmcs); + +int +pfm_mod_read_pmds(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_read_pmds(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_read_pmds); + +/* + * Only call this function when a process it trying to + * write the debug registers (reading is always allowed) + */ +int +pfm_use_debug_registers(struct task_struct *task) +{ + pfm_context_t *ctx = task->thread.pfm_context; + unsigned long flags; + int ret = 0; + + if (pmu_conf->use_rr_dbregs == 0) return 0; + + DPRINT(("called for [%d]\n", task->pid)); + + /* + * do it only once + */ + if (task->thread.flags & IA64_THREAD_DBG_VALID) return 0; + + /* + * Even on SMP, we do not need to use an atomic here because + * the only way in is via ptrace() and this is possible only when the + * process is stopped. Even in the case where the ctxsw out is not totally + * completed by the time we come here, there is no way the 'stopped' process + * could be in the middle of fiddling with the pfm_write_ibr_dbr() routine. + * So this is always safe. + */ + if (ctx && ctx->ctx_fl_using_dbreg == 1) return -1; + + LOCK_PFS(flags); + + /* + * We cannot allow setting breakpoints when system wide monitoring + * sessions are using the debug registers. + */ + if (pfm_sessions.pfs_sys_use_dbregs> 0) + ret = -1; + else + pfm_sessions.pfs_ptrace_use_dbregs++; + + DPRINT(("ptrace_use_dbregs=%u sys_use_dbregs=%u by [%d] ret = %d\n", + pfm_sessions.pfs_ptrace_use_dbregs, + pfm_sessions.pfs_sys_use_dbregs, + task->pid, ret)); + + UNLOCK_PFS(flags); + + return ret; +} + +/* + * This function is called for every task that exits with the + * IA64_THREAD_DBG_VALID set. This indicates a task which was + * able to use the debug registers for debugging purposes via + * ptrace(). Therefore we know it was not using them for + * perfmormance monitoring, so we only decrement the number + * of "ptraced" debug register users to keep the count up to date + */ +int +pfm_release_debug_registers(struct task_struct *task) +{ + unsigned long flags; + int ret; + + if (pmu_conf->use_rr_dbregs == 0) return 0; + + LOCK_PFS(flags); + if (pfm_sessions.pfs_ptrace_use_dbregs == 0) { + printk(KERN_ERR "perfmon: invalid release for [%d] ptrace_use_dbregs=0\n", task->pid); + ret = -1; + } else { + pfm_sessions.pfs_ptrace_use_dbregs--; + ret = 0; + } + UNLOCK_PFS(flags); + + return ret; +} + +static int +pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task; + pfm_buffer_fmt_t *fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int state, is_system; + int ret = 0; + + state = ctx->ctx_state; + fmt = ctx->ctx_buf_fmt; + is_system = ctx->ctx_fl_system; + task = PFM_CTX_TASK(ctx); + + switch(state) { + case PFM_CTX_MASKED: + break; + case PFM_CTX_LOADED: + if (CTX_HAS_SMPL(ctx) && fmt->fmt_restart_active) break; + /* fall through */ + case PFM_CTX_UNLOADED: + case PFM_CTX_ZOMBIE: + DPRINT(("invalid state=%d\n", state)); + return -EBUSY; + default: + DPRINT(("state=%d, cannot operate (no active_restart handler)\n", state)); + return -EINVAL; + } + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + + /* sanity check */ + if (unlikely(task == NULL)) { + printk(KERN_ERR "perfmon: [%d] pfm_restart no task\n", current->pid); + return -EINVAL; + } + + if (task == current || is_system) { + + fmt = ctx->ctx_buf_fmt; + + DPRINT(("restarting self %d ovfl=0x%lx\n", + task->pid, + ctx->ctx_ovfl_regs[0])); + + if (CTX_HAS_SMPL(ctx)) { + + prefetch(ctx->ctx_smpl_hdr); + + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 0; + + if (state == PFM_CTX_LOADED) + ret = pfm_buf_fmt_restart_active(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + else + ret = pfm_buf_fmt_restart(fmt, task, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + } else { + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 1; + } + + if (ret == 0) { + if (rst_ctrl.bits.reset_ovfl_pmds) + pfm_reset_regs(ctx, ctx->ctx_ovfl_regs, PFM_PMD_LONG_RESET); + + if (rst_ctrl.bits.mask_monitoring == 0) { + DPRINT(("resuming monitoring for [%d]\n", task->pid)); + + if (state == PFM_CTX_MASKED) pfm_restore_monitoring(task); + } else { + DPRINT(("keeping monitoring stopped for [%d]\n", task->pid)); + + // cannot use pfm_stop_monitoring(task, regs); + } + } + /* + * clear overflowed PMD mask to remove any stale information + */ + ctx->ctx_ovfl_regs[0] = 0UL; + + /* + * back to LOADED state + */ + ctx->ctx_state = PFM_CTX_LOADED; + + /* + * XXX: not really useful for self monitoring + */ + ctx->ctx_fl_can_restart = 0; + + return 0; + } + + /* + * restart another task + */ + + /* + * When PFM_CTX_MASKED, we cannot issue a restart before the previous + * one is seen by the task. + */ + if (state == PFM_CTX_MASKED) { + if (ctx->ctx_fl_can_restart == 0) return -EINVAL; + /* + * will prevent subsequent restart before this one is + * seen by other task + */ + ctx->ctx_fl_can_restart = 0; + } + + /* + * if blocking, then post the semaphore is PFM_CTX_MASKED, i.e. + * the task is blocked or on its way to block. That's the normal + * restart path. If the monitoring is not masked, then the task + * can be actively monitoring and we cannot directly intervene. + * Therefore we use the trap mechanism to catch the task and + * force it to reset the buffer/reset PMDs. + * + * if non-blocking, then we ensure that the task will go into + * pfm_handle_work() before returning to user mode. + * + * We cannot explicitely reset another task, it MUST always + * be done by the task itself. This works for system wide because + * the tool that is controlling the session is logically doing + * "self-monitoring". + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && state == PFM_CTX_MASKED) { + DPRINT(("unblocking [%d] \n", task->pid)); + complete(&ctx->ctx_restart_done); + } else { + DPRINT(("[%d] armed exit trap\n", task->pid)); + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET; + + PFM_SET_WORK_PENDING(task, 1); + + pfm_set_task_notify(task); + + /* + * XXX: send reschedule if task runs on another CPU + */ + } + return 0; +} + +static int +pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + unsigned int m = *(unsigned int *)arg; + + pfm_sysctl.debug = m == 0 ? 0 : 1; + + printk(KERN_INFO "perfmon debugging %s (timing reset)\n", pfm_sysctl.debug ? "on" : "off"); + + if (m == 0) { + memset(pfm_stats, 0, sizeof(pfm_stats)); + for(m=0; m < NR_CPUS; m++) pfm_stats[m].pfm_ovfl_intr_cycles_min = ~0UL; + } + return 0; +} + +/* + * arg can be NULL and count can be zero for this function + */ +static int +pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct thread_struct *thread = NULL; + struct task_struct *task; + pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg; + unsigned long flags; + dbreg_t dbreg; + unsigned int rnum; + int first_time; + int ret = 0, state; + int i, can_access_pmu = 0; + int is_system, is_loaded; + + if (pmu_conf->use_rr_dbregs == 0) return -EINVAL; + + state = ctx->ctx_state; + is_loaded = state == PFM_CTX_LOADED ? 1 : 0; + is_system = ctx->ctx_fl_system; + task = ctx->ctx_task; + + if (state == PFM_CTX_ZOMBIE) return -EINVAL; + + /* + * on both UP and SMP, we can only write to the PMC when the task is + * the owner of the local PMU. + */ + if (is_loaded) { + thread = &task->thread; + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (unlikely(is_system && ctx->ctx_cpu != smp_processor_id())) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; + } + + /* + * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w + * ensuring that no real breakpoint can be installed via this call. + * + * IMPORTANT: regs can be NULL in this function + */ + + first_time = ctx->ctx_fl_using_dbreg == 0; + + /* + * don't bother if we are loaded and task is being debugged + */ + if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) { + DPRINT(("debug registers already in use for [%d]\n", task->pid)); + return -EBUSY; + } + + /* + * check for debug registers in system wide mode + * + * If though a check is done in pfm_context_load(), + * we must repeat it here, in case the registers are + * written after the context is loaded + */ + if (is_loaded) { + LOCK_PFS(flags); + + if (first_time && is_system) { + if (pfm_sessions.pfs_ptrace_use_dbregs) + ret = -EBUSY; + else + pfm_sessions.pfs_sys_use_dbregs++; + } + UNLOCK_PFS(flags); + } + + if (ret != 0) return ret; + + /* + * mark ourself as user of the debug registers for + * perfmon purposes. + */ + ctx->ctx_fl_using_dbreg = 1; + + /* + * clear hardware registers to make sure we don't + * pick up stale state. + * + * for a system wide session, we do not use + * thread.dbr, thread.ibr because this process + * never leaves the current CPU and the state + * is shared by all processes running on it + */ + if (first_time && can_access_pmu) { + DPRINT(("[%d] clearing ibrs, dbrs\n", task->pid)); + for (i=0; i < pmu_conf->num_ibrs; i++) { + ia64_set_ibr(i, 0UL); + ia64_dv_serialize_instruction(); + } + ia64_srlz_i(); + for (i=0; i < pmu_conf->num_dbrs; i++) { + ia64_set_dbr(i, 0UL); + ia64_dv_serialize_data(); + } + ia64_srlz_d(); + } + + /* + * Now install the values into the registers + */ + for (i = 0; i < count; i++, req++) { + + rnum = req->dbreg_num; + dbreg.val = req->dbreg_value; + + ret = -EINVAL; + + if ((mode == PFM_CODE_RR && rnum >= PFM_NUM_IBRS) || ((mode == PFM_DATA_RR) && rnum >= PFM_NUM_DBRS)) { + DPRINT(("invalid register %u val=0x%lx mode=%d i=%d count=%d\n", + rnum, dbreg.val, mode, i, count)); + + goto abort_mission; + } + + /* + * make sure we do not install enabled breakpoint + */ + if (rnum & 0x1) { + if (mode == PFM_CODE_RR) + dbreg.ibr.ibr_x = 0; + else + dbreg.dbr.dbr_r = dbreg.dbr.dbr_w = 0; + } + + PFM_REG_RETFLAG_SET(req->dbreg_flags, 0); + + /* + * Debug registers, just like PMC, can only be modified + * by a kernel call. Moreover, perfmon() access to those + * registers are centralized in this routine. The hardware + * does not modify the value of these registers, therefore, + * if we save them as they are written, we can avoid having + * to save them on context switch out. This is made possible + * by the fact that when perfmon uses debug registers, ptrace() + * won't be able to modify them concurrently. + */ + if (mode == PFM_CODE_RR) { + CTX_USED_IBR(ctx, rnum); + + if (can_access_pmu) { + ia64_set_ibr(rnum, dbreg.val); + ia64_dv_serialize_instruction(); + } + + ctx->ctx_ibrs[rnum] = dbreg.val; + + DPRINT(("write ibr%u=0x%lx used_ibrs=0x%x ld=%d apmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_ibrs[0], is_loaded, can_access_pmu)); + } else { + CTX_USED_DBR(ctx, rnum); + + if (can_access_pmu) { + ia64_set_dbr(rnum, dbreg.val); + ia64_dv_serialize_data(); + } + ctx->ctx_dbrs[rnum] = dbreg.val; + + DPRINT(("write dbr%u=0x%lx used_dbrs=0x%x ld=%d apmu=%d\n", + rnum, dbreg.val, ctx->ctx_used_dbrs[0], is_loaded, can_access_pmu)); + } + } + + return 0; + +abort_mission: + /* + * in case it was our first attempt, we undo the global modifications + */ + if (first_time) { + LOCK_PFS(flags); + if (ctx->ctx_fl_system) { + pfm_sessions.pfs_sys_use_dbregs--; + } + UNLOCK_PFS(flags); + ctx->ctx_fl_using_dbreg = 0; + } + /* + * install error return flag + */ + PFM_REG_RETFLAG_SET(req->dbreg_flags, PFM_REG_RETFL_EINVAL); + + return ret; +} + +static int +pfm_write_ibrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_CODE_RR, ctx, arg, count, regs); +} + +static int +pfm_write_dbrs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + return pfm_write_ibr_dbr(PFM_DATA_RR, ctx, arg, count, regs); +} + +int +pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_write_ibrs(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_write_ibrs); + +int +pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs) +{ + pfm_context_t *ctx; + + if (req == NULL) return -EINVAL; + + ctx = GET_PMU_CTX(); + + if (ctx == NULL) return -EINVAL; + + /* + * for now limit to current task, which is enough when calling + * from overflow handler + */ + if (task != current && ctx->ctx_fl_system == 0) return -EBUSY; + + return pfm_write_dbrs(ctx, req, nreq, regs); +} +EXPORT_SYMBOL(pfm_mod_write_dbrs); + + +static int +pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_features_t *req = (pfarg_features_t *)arg; + + req->ft_version = PFM_VERSION; + return 0; +} + +static int +pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct pt_regs *tregs; + struct task_struct *task = PFM_CTX_TASK(ctx); + int state, is_system; + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + /* + * context must be attached to issue the stop command (includes LOADED,MASKED,ZOMBIE) + */ + if (state == PFM_CTX_UNLOADED) return -EINVAL; + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + DPRINT(("task [%d] ctx_state=%d is_system=%d\n", + PFM_CTX_TASK(ctx)->pid, + state, + is_system)); + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (is_system) { + /* + * Update local PMU first + * + * disable dcr pp + */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP); + ia64_srlz_i(); + + /* + * update local cpuinfo + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + /* + * stop monitoring, does srlz.i + */ + pfm_clear_psr_pp(); + + /* + * stop monitoring in the caller + */ + ia64_psr(regs)->pp = 0; + + return 0; + } + /* + * per-task mode + */ + + if (task == current) { + /* stop monitoring at kernel level */ + pfm_clear_psr_up(); + + /* + * stop monitoring at the user level + */ + ia64_psr(regs)->up = 0; + } else { + tregs = task_pt_regs(task); + + /* + * stop monitoring at the user level + */ + ia64_psr(tregs)->up = 0; + + /* + * monitoring disabled in kernel at next reschedule + */ + ctx->ctx_saved_psr_up = 0; + DPRINT(("task=[%d]\n", task->pid)); + } + return 0; +} + + +static int +pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct pt_regs *tregs; + int state, is_system; + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + if (state != PFM_CTX_LOADED) return -EINVAL; + + /* + * In system wide and when the context is loaded, access can only happen + * when the caller is running on the CPU being monitored by the session. + * It does not have to be the owner (ctx_task) of the context per se. + */ + if (is_system && ctx->ctx_cpu != smp_processor_id()) { + DPRINT(("should be running on CPU%d\n", ctx->ctx_cpu)); + return -EBUSY; + } + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (is_system) { + + /* + * set user level psr.pp for the caller + */ + ia64_psr(regs)->pp = 1; + + /* + * now update the local PMU and cpuinfo + */ + PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); + + /* + * start monitoring at kernel level + */ + pfm_set_psr_pp(); + + /* enable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP); + ia64_srlz_i(); + + return 0; + } + + /* + * per-process mode + */ + + if (ctx->ctx_task == current) { + + /* start monitoring at kernel level */ + pfm_set_psr_up(); + + /* + * activate monitoring at user level + */ + ia64_psr(regs)->up = 1; + + } else { + tregs = task_pt_regs(ctx->ctx_task); + + /* + * start monitoring at the kernel level the next + * time the task is scheduled + */ + ctx->ctx_saved_psr_up = IA64_PSR_UP; + + /* + * activate monitoring at user level + */ + ia64_psr(tregs)->up = 1; + } + return 0; +} + +static int +pfm_get_pmc_reset(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + pfarg_reg_t *req = (pfarg_reg_t *)arg; + unsigned int cnum; + int i; + int ret = -EINVAL; + + for (i = 0; i < count; i++, req++) { + + cnum = req->reg_num; + + if (!PMC_IS_IMPL(cnum)) goto abort_mission; + + req->reg_value = PMC_DFL_VAL(cnum); + + PFM_REG_RETFLAG_SET(req->reg_flags, 0); + + DPRINT(("pmc_reset_val pmc[%u]=0x%lx\n", cnum, req->reg_value)); + } + return 0; + +abort_mission: + PFM_REG_RETFLAG_SET(req->reg_flags, PFM_REG_RETFL_EINVAL); + return ret; +} + +static int +pfm_check_task_exist(pfm_context_t *ctx) +{ + struct task_struct *g, *t; + int ret = -ESRCH; + + read_lock(&tasklist_lock); + + do_each_thread (g, t) { + if (t->thread.pfm_context == ctx) { + ret = 0; + break; + } + } while_each_thread (g, t); + + read_unlock(&tasklist_lock); + + DPRINT(("pfm_check_task_exist: ret=%d ctx=%p\n", ret, ctx)); + + return ret; +} + +static int +pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task; + struct thread_struct *thread; + struct pfm_context_t *old; + unsigned long flags; +#ifndef CONFIG_SMP + struct task_struct *owner_task = NULL; +#endif + pfarg_load_t *req = (pfarg_load_t *)arg; + unsigned long *pmcs_source, *pmds_source; + int the_cpu; + int ret = 0; + int state, is_system, set_dbregs = 0; + + state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + /* + * can only load from unloaded or terminated state + */ + if (state != PFM_CTX_UNLOADED) { + DPRINT(("cannot load to [%d], invalid ctx_state=%d\n", + req->load_pid, + ctx->ctx_state)); + return -EBUSY; + } + + DPRINT(("load_pid [%d] using_dbreg=%d\n", req->load_pid, ctx->ctx_fl_using_dbreg)); + + if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) { + DPRINT(("cannot use blocking mode on self\n")); + return -EINVAL; + } + + ret = pfm_get_task(ctx, req->load_pid, &task); + if (ret) { + DPRINT(("load_pid [%d] get_task=%d\n", req->load_pid, ret)); + return ret; + } + + ret = -EINVAL; + + /* + * system wide is self monitoring only + */ + if (is_system && task != current) { + DPRINT(("system wide is self monitoring only load_pid=%d\n", + req->load_pid)); + goto error; + } + + thread = &task->thread; + + ret = 0; + /* + * cannot load a context which is using range restrictions, + * into a task that is being debugged. + */ + if (ctx->ctx_fl_using_dbreg) { + if (thread->flags & IA64_THREAD_DBG_VALID) { + ret = -EBUSY; + DPRINT(("load_pid [%d] task is debugged, cannot load range restrictions\n", req->load_pid)); + goto error; + } + LOCK_PFS(flags); + + if (is_system) { + if (pfm_sessions.pfs_ptrace_use_dbregs) { + DPRINT(("cannot load [%d] dbregs in use\n", task->pid)); + ret = -EBUSY; + } else { + pfm_sessions.pfs_sys_use_dbregs++; + DPRINT(("load [%d] increased sys_use_dbreg=%u\n", task->pid, pfm_sessions.pfs_sys_use_dbregs)); + set_dbregs = 1; + } + } + + UNLOCK_PFS(flags); + + if (ret) goto error; + } + + /* + * SMP system-wide monitoring implies self-monitoring. + * + * The programming model expects the task to + * be pinned on a CPU throughout the session. + * Here we take note of the current CPU at the + * time the context is loaded. No call from + * another CPU will be allowed. + * + * The pinning via shed_setaffinity() + * must be done by the calling task prior + * to this call. + * + * systemwide: keep track of CPU this session is supposed to run on + */ + the_cpu = ctx->ctx_cpu = smp_processor_id(); + + ret = -EBUSY; + /* + * now reserve the session + */ + ret = pfm_reserve_session(current, is_system, the_cpu); + if (ret) goto error; + + /* + * task is necessarily stopped at this point. + * + * If the previous context was zombie, then it got removed in + * pfm_save_regs(). Therefore we should not see it here. + * If we see a context, then this is an active context + * + * XXX: needs to be atomic + */ + DPRINT(("before cmpxchg() old_ctx=%p new_ctx=%p\n", + thread->pfm_context, ctx)); + + ret = -EBUSY; + old = ia64_cmpxchg(acq, &thread->pfm_context, NULL, ctx, sizeof(pfm_context_t *)); + if (old != NULL) { + DPRINT(("load_pid [%d] already has a context\n", req->load_pid)); + goto error_unres; + } + + pfm_reset_msgq(ctx); + + ctx->ctx_state = PFM_CTX_LOADED; + + /* + * link context to task + */ + ctx->ctx_task = task; + + if (is_system) { + /* + * we load as stopped + */ + PFM_CPUINFO_SET(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); + } else { + thread->flags |= IA64_THREAD_PM_VALID; + } + + /* + * propagate into thread-state + */ + pfm_copy_pmds(task, ctx); + pfm_copy_pmcs(task, ctx); + + pmcs_source = thread->pmcs; + pmds_source = thread->pmds; + + /* + * always the case for system-wide + */ + if (task == current) { + + if (is_system == 0) { + + /* allow user level control */ + ia64_psr(regs)->sp = 0; + DPRINT(("clearing psr.sp for [%d]\n", task->pid)); + + SET_LAST_CPU(ctx, smp_processor_id()); + INC_ACTIVATION(); + SET_ACTIVATION(ctx); +#ifndef CONFIG_SMP + /* + * push the other task out, if any + */ + owner_task = GET_PMU_OWNER(); + if (owner_task) pfm_lazy_save_regs(owner_task); +#endif + } + /* + * load all PMD from ctx to PMU (as opposed to thread state) + * restore all PMC from ctx to PMU + */ + pfm_restore_pmds(pmds_source, ctx->ctx_all_pmds[0]); + pfm_restore_pmcs(pmcs_source, ctx->ctx_all_pmcs[0]); + + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + /* + * guaranteed safe by earlier check against DBG_VALID + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + /* + * set new ownership + */ + SET_PMU_OWNER(task, ctx); + + DPRINT(("context loaded on PMU for [%d]\n", task->pid)); + } else { + /* + * when not current, task MUST be stopped, so this is safe + */ + regs = task_pt_regs(task); + + /* force a full reload */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* initial saved psr (stopped) */ + ctx->ctx_saved_psr_up = 0UL; + ia64_psr(regs)->up = ia64_psr(regs)->pp = 0; + } + + ret = 0; + +error_unres: + if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu); +error: + /* + * we must undo the dbregs setting (for system-wide) + */ + if (ret && set_dbregs) { + LOCK_PFS(flags); + pfm_sessions.pfs_sys_use_dbregs--; + UNLOCK_PFS(flags); + } + /* + * release task, there is now a link with the context + */ + if (is_system == 0 && task != current) { + pfm_put_task(task); + + if (ret == 0) { + ret = pfm_check_task_exist(ctx); + if (ret) { + ctx->ctx_state = PFM_CTX_UNLOADED; + ctx->ctx_task = NULL; + } + } + } + return ret; +} + +/* + * in this function, we do not need to increase the use count + * for the task via get_task_struct(), because we hold the + * context lock. If the task were to disappear while having + * a context attached, it would go through pfm_exit_thread() + * which also grabs the context lock and would therefore be blocked + * until we are here. + */ +static void pfm_flush_pmds(struct task_struct *, pfm_context_t *ctx); + +static int +pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +{ + struct task_struct *task = PFM_CTX_TASK(ctx); + struct pt_regs *tregs; + int prev_state, is_system; + int ret; + + DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); + + prev_state = ctx->ctx_state; + is_system = ctx->ctx_fl_system; + + /* + * unload only when necessary + */ + if (prev_state == PFM_CTX_UNLOADED) { + DPRINT(("ctx_state=%d, nothing to do\n", prev_state)); + return 0; + } + + /* + * clear psr and dcr bits + */ + ret = pfm_stop(ctx, NULL, 0, regs); + if (ret) return ret; + + ctx->ctx_state = PFM_CTX_UNLOADED; + + /* + * in system mode, we need to update the PMU directly + * and the user level state of the caller, which may not + * necessarily be the creator of the context. + */ + if (is_system) { + + /* + * Update cpuinfo + * + * local PMU is taken care of in pfm_stop() + */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); + PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); + + /* + * save PMDs in context + * release ownership + */ + pfm_flush_pmds(current, ctx); + + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + */ + if (prev_state != PFM_CTX_ZOMBIE) + pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); + + /* + * disconnect context from task + */ + task->thread.pfm_context = NULL; + /* + * disconnect task from context + */ + ctx->ctx_task = NULL; + + /* + * There is nothing more to cleanup here. + */ + return 0; + } + + /* + * per-task mode + */ + tregs = task == current ? regs : task_pt_regs(task); + + if (task == current) { + /* + * cancel user level control + */ + ia64_psr(regs)->sp = 1; + + DPRINT(("setting psr.sp for [%d]\n", task->pid)); + } + /* + * save PMDs to context + * release ownership + */ + pfm_flush_pmds(task, ctx); + + /* + * at this point we are done with the PMU + * so we can unreserve the resource. + * + * when state was ZOMBIE, we have already unreserved. + */ + if (prev_state != PFM_CTX_ZOMBIE) + pfm_unreserve_session(ctx, 0 , ctx->ctx_cpu); + + /* + * reset activation counter and psr + */ + ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; + SET_LAST_CPU(ctx, -1); + + /* + * PMU state will not be restored + */ + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + /* + * break links between context and task + */ + task->thread.pfm_context = NULL; + ctx->ctx_task = NULL; + + PFM_SET_WORK_PENDING(task, 0); + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + ctx->ctx_fl_can_restart = 0; + ctx->ctx_fl_going_zombie = 0; + + DPRINT(("disconnected [%d] from context\n", task->pid)); + + return 0; +} + + +/* + * called only from exit_thread(): task == current + * we come here only if current has a context attached (loaded or masked) + */ +void +pfm_exit_thread(struct task_struct *task) +{ + pfm_context_t *ctx; + unsigned long flags; + struct pt_regs *regs = task_pt_regs(task); + int ret, state; + int free_ok = 0; + + ctx = PFM_GET_CTX(task); + + PROTECT_CTX(ctx, flags); + + DPRINT(("state=%d task [%d]\n", ctx->ctx_state, task->pid)); + + state = ctx->ctx_state; + switch(state) { + case PFM_CTX_UNLOADED: + /* + * only comes to thios function if pfm_context is not NULL, i.e., cannot + * be in unloaded state + */ + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] ctx unloaded\n", task->pid); + break; + case PFM_CTX_LOADED: + case PFM_CTX_MASKED: + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task->pid, state, ret); + } + DPRINT(("ctx unloaded for current state was %d\n", state)); + + pfm_end_notify_user(ctx); + break; + case PFM_CTX_ZOMBIE: + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] state=%d unload failed %d\n", task->pid, state, ret); + } + free_ok = 1; + break; + default: + printk(KERN_ERR "perfmon: pfm_exit_thread [%d] unexpected state=%d\n", task->pid, state); + break; + } + UNPROTECT_CTX(ctx, flags); + + { u64 psr = pfm_get_psr(); + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + BUG_ON(GET_PMU_OWNER()); + BUG_ON(ia64_psr(regs)->up); + BUG_ON(ia64_psr(regs)->pp); + } + + /* + * All memory free operations (especially for vmalloc'ed memory) + * MUST be done with interrupts ENABLED. + */ + if (free_ok) pfm_context_free(ctx); +} + +/* + * functions MUST be listed in the increasing order of their index (see permfon.h) + */ +#define PFM_CMD(name, flags, arg_count, arg_type, getsz) { name, #name, flags, arg_count, sizeof(arg_type), getsz } +#define PFM_CMD_S(name, flags) { name, #name, flags, 0, 0, NULL } +#define PFM_CMD_PCLRWS (PFM_CMD_FD|PFM_CMD_ARG_RW|PFM_CMD_STOP) +#define PFM_CMD_PCLRW (PFM_CMD_FD|PFM_CMD_ARG_RW) +#define PFM_CMD_NONE { NULL, "no-cmd", 0, 0, 0, NULL} + +static pfm_cmd_desc_t pfm_cmd_tab[]={ +/* 0 */PFM_CMD_NONE, +/* 1 */PFM_CMD(pfm_write_pmcs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 2 */PFM_CMD(pfm_write_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 3 */PFM_CMD(pfm_read_pmds, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 4 */PFM_CMD_S(pfm_stop, PFM_CMD_PCLRWS), +/* 5 */PFM_CMD_S(pfm_start, PFM_CMD_PCLRWS), +/* 6 */PFM_CMD_NONE, +/* 7 */PFM_CMD_NONE, +/* 8 */PFM_CMD(pfm_context_create, PFM_CMD_ARG_RW, 1, pfarg_context_t, pfm_ctx_getsize), +/* 9 */PFM_CMD_NONE, +/* 10 */PFM_CMD_S(pfm_restart, PFM_CMD_PCLRW), +/* 11 */PFM_CMD_NONE, +/* 12 */PFM_CMD(pfm_get_features, PFM_CMD_ARG_RW, 1, pfarg_features_t, NULL), +/* 13 */PFM_CMD(pfm_debug, 0, 1, unsigned int, NULL), +/* 14 */PFM_CMD_NONE, +/* 15 */PFM_CMD(pfm_get_pmc_reset, PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, pfarg_reg_t, NULL), +/* 16 */PFM_CMD(pfm_context_load, PFM_CMD_PCLRWS, 1, pfarg_load_t, NULL), +/* 17 */PFM_CMD_S(pfm_context_unload, PFM_CMD_PCLRWS), +/* 18 */PFM_CMD_NONE, +/* 19 */PFM_CMD_NONE, +/* 20 */PFM_CMD_NONE, +/* 21 */PFM_CMD_NONE, +/* 22 */PFM_CMD_NONE, +/* 23 */PFM_CMD_NONE, +/* 24 */PFM_CMD_NONE, +/* 25 */PFM_CMD_NONE, +/* 26 */PFM_CMD_NONE, +/* 27 */PFM_CMD_NONE, +/* 28 */PFM_CMD_NONE, +/* 29 */PFM_CMD_NONE, +/* 30 */PFM_CMD_NONE, +/* 31 */PFM_CMD_NONE, +/* 32 */PFM_CMD(pfm_write_ibrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL), +/* 33 */PFM_CMD(pfm_write_dbrs, PFM_CMD_PCLRWS, PFM_CMD_ARG_MANY, pfarg_dbreg_t, NULL) +}; +#define PFM_CMD_COUNT (sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t)) + +static int +pfm_check_task_state(pfm_context_t *ctx, int cmd, unsigned long flags) +{ + struct task_struct *task; + int state, old_state; + +recheck: + state = ctx->ctx_state; + task = ctx->ctx_task; + + if (task == NULL) { + DPRINT(("context %d no task, state=%d\n", ctx->ctx_fd, state)); + return 0; + } + + DPRINT(("context %d state=%d [%d] task_state=%ld must_stop=%d\n", + ctx->ctx_fd, + state, + task->pid, + task->state, PFM_CMD_STOPPED(cmd))); + + /* + * self-monitoring always ok. + * + * for system-wide the caller can either be the creator of the + * context (to one to which the context is attached to) OR + * a task running on the same CPU as the session. + */ + if (task == current || ctx->ctx_fl_system) return 0; + + /* + * we are monitoring another thread + */ + switch(state) { + case PFM_CTX_UNLOADED: + /* + * if context is UNLOADED we are safe to go + */ + return 0; + case PFM_CTX_ZOMBIE: + /* + * no command can operate on a zombie context + */ + DPRINT(("cmd %d state zombie cannot operate on context\n", cmd)); + return -EINVAL; + case PFM_CTX_MASKED: + /* + * PMU state has been saved to software even though + * the thread may still be running. + */ + if (cmd != PFM_UNLOAD_CONTEXT) return 0; + } + + /* + * context is LOADED or MASKED. Some commands may need to have + * the task stopped. + * + * We could lift this restriction for UP but it would mean that + * the user has no guarantee the task would not run between + * two successive calls to perfmonctl(). That's probably OK. + * If this user wants to ensure the task does not run, then + * the task must be stopped. + */ + if (PFM_CMD_STOPPED(cmd)) { + if ((task->state != TASK_STOPPED) && (task->state != TASK_TRACED)) { + DPRINT(("[%d] task not in stopped state\n", task->pid)); + return -EBUSY; + } + /* + * task is now stopped, wait for ctxsw out + * + * This is an interesting point in the code. + * We need to unprotect the context because + * the pfm_save_regs() routines needs to grab + * the same lock. There are danger in doing + * this because it leaves a window open for + * another task to get access to the context + * and possibly change its state. The one thing + * that is not possible is for the context to disappear + * because we are protected by the VFS layer, i.e., + * get_fd()/put_fd(). + */ + old_state = state; + + UNPROTECT_CTX(ctx, flags); + + wait_task_inactive(task); + + PROTECT_CTX(ctx, flags); + + /* + * we must recheck to verify if state has changed + */ + if (ctx->ctx_state != old_state) { + DPRINT(("old_state=%d new_state=%d\n", old_state, ctx->ctx_state)); + goto recheck; + } + } + return 0; +} + +/* + * system-call entry point (must return long) + */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void __user *arg, int count) +{ + struct file *file = NULL; + pfm_context_t *ctx = NULL; + unsigned long flags = 0UL; + void *args_k = NULL; + long ret; /* will expand int return types */ + size_t base_sz, sz, xtra_sz = 0; + int narg, completed_args = 0, call_made = 0, cmd_flags; + int (*func)(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); + int (*getsize)(void *arg, size_t *sz); +#define PFM_MAX_ARGSIZE 4096 + + /* + * reject any call if perfmon was disabled at initialization + */ + if (unlikely(pmu_conf == NULL)) return -ENOSYS; + + if (unlikely(cmd < 0 || cmd >= PFM_CMD_COUNT)) { + DPRINT(("invalid cmd=%d\n", cmd)); + return -EINVAL; + } + + func = pfm_cmd_tab[cmd].cmd_func; + narg = pfm_cmd_tab[cmd].cmd_narg; + base_sz = pfm_cmd_tab[cmd].cmd_argsize; + getsize = pfm_cmd_tab[cmd].cmd_getsize; + cmd_flags = pfm_cmd_tab[cmd].cmd_flags; + + if (unlikely(func == NULL)) { + DPRINT(("invalid cmd=%d\n", cmd)); + return -EINVAL; + } + + DPRINT(("cmd=%s idx=%d narg=0x%x argsz=%lu count=%d\n", + PFM_CMD_NAME(cmd), + cmd, + narg, + base_sz, + count)); + + /* + * check if number of arguments matches what the command expects + */ + if (unlikely((narg == PFM_CMD_ARG_MANY && count <= 0) || (narg > 0 && narg != count))) + return -EINVAL; + +restart_args: + sz = xtra_sz + base_sz*count; + /* + * limit abuse to min page size + */ + if (unlikely(sz > PFM_MAX_ARGSIZE)) { + printk(KERN_ERR "perfmon: [%d] argument too big %lu\n", current->pid, sz); + return -E2BIG; + } + + /* + * allocate default-sized argument buffer + */ + if (likely(count && args_k == NULL)) { + args_k = kmalloc(PFM_MAX_ARGSIZE, GFP_KERNEL); + if (args_k == NULL) return -ENOMEM; + } + + ret = -EFAULT; + + /* + * copy arguments + * + * assume sz = 0 for command without parameters + */ + if (sz && copy_from_user(args_k, arg, sz)) { + DPRINT(("cannot copy_from_user %lu bytes @%p\n", sz, arg)); + goto error_args; + } + + /* + * check if command supports extra parameters + */ + if (completed_args == 0 && getsize) { + /* + * get extra parameters size (based on main argument) + */ + ret = (*getsize)(args_k, &xtra_sz); + if (ret) goto error_args; + + completed_args = 1; + + DPRINT(("restart_args sz=%lu xtra_sz=%lu\n", sz, xtra_sz)); + + /* retry if necessary */ + if (likely(xtra_sz)) goto restart_args; + } + + if (unlikely((cmd_flags & PFM_CMD_FD) == 0)) goto skip_fd; + + ret = -EBADF; + + file = fget(fd); + if (unlikely(file == NULL)) { + DPRINT(("invalid fd %d\n", fd)); + goto error_args; + } + if (unlikely(PFM_IS_FILE(file) == 0)) { + DPRINT(("fd %d not related to perfmon\n", fd)); + goto error_args; + } + + ctx = (pfm_context_t *)file->private_data; + if (unlikely(ctx == NULL)) { + DPRINT(("no context for fd %d\n", fd)); + goto error_args; + } + prefetch(&ctx->ctx_state); + + PROTECT_CTX(ctx, flags); + + /* + * check task is stopped + */ + ret = pfm_check_task_state(ctx, cmd, flags); + if (unlikely(ret)) goto abort_locked; + +skip_fd: + ret = (*func)(ctx, args_k, count, task_pt_regs(current)); + + call_made = 1; + +abort_locked: + if (likely(ctx)) { + DPRINT(("context unlocked\n")); + UNPROTECT_CTX(ctx, flags); + } + + /* copy argument back to user, if needed */ + if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT; + +error_args: + if (file) + fput(file); + + kfree(args_k); + + DPRINT(("cmd=%s ret=%ld\n", PFM_CMD_NAME(cmd), ret)); + + return ret; +} + +static void +pfm_resume_after_ovfl(pfm_context_t *ctx, unsigned long ovfl_regs, struct pt_regs *regs) +{ + pfm_buffer_fmt_t *fmt = ctx->ctx_buf_fmt; + pfm_ovfl_ctrl_t rst_ctrl; + int state; + int ret = 0; + + state = ctx->ctx_state; + /* + * Unlock sampling buffer and reset index atomically + * XXX: not really needed when blocking + */ + if (CTX_HAS_SMPL(ctx)) { + + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 0; + + if (state == PFM_CTX_LOADED) + ret = pfm_buf_fmt_restart_active(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + else + ret = pfm_buf_fmt_restart(fmt, current, &rst_ctrl, ctx->ctx_smpl_hdr, regs); + } else { + rst_ctrl.bits.mask_monitoring = 0; + rst_ctrl.bits.reset_ovfl_pmds = 1; + } + + if (ret == 0) { + if (rst_ctrl.bits.reset_ovfl_pmds) { + pfm_reset_regs(ctx, &ovfl_regs, PFM_PMD_LONG_RESET); + } + if (rst_ctrl.bits.mask_monitoring == 0) { + DPRINT(("resuming monitoring\n")); + if (ctx->ctx_state == PFM_CTX_MASKED) pfm_restore_monitoring(current); + } else { + DPRINT(("stopping monitoring\n")); + //pfm_stop_monitoring(current, regs); + } + ctx->ctx_state = PFM_CTX_LOADED; + } +} + +/* + * context MUST BE LOCKED when calling + * can only be called for current + */ +static void +pfm_context_force_terminate(pfm_context_t *ctx, struct pt_regs *regs) +{ + int ret; + + DPRINT(("entering for [%d]\n", current->pid)); + + ret = pfm_context_unload(ctx, NULL, 0, regs); + if (ret) { + printk(KERN_ERR "pfm_context_force_terminate: [%d] unloaded failed with %d\n", current->pid, ret); + } + + /* + * and wakeup controlling task, indicating we are now disconnected + */ + wake_up_interruptible(&ctx->ctx_zombieq); + + /* + * given that context is still locked, the controlling + * task will only get access when we return from + * pfm_handle_work(). + */ +} + +static int pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds); + /* + * pfm_handle_work() can be called with interrupts enabled + * (TIF_NEED_RESCHED) or disabled. The down_interruptible + * call may sleep, therefore we must re-enable interrupts + * to avoid deadlocks. It is safe to do so because this function + * is called ONLY when returning to user level (PUStk=1), in which case + * there is no risk of kernel stack overflow due to deep + * interrupt nesting. + */ +void +pfm_handle_work(void) +{ + pfm_context_t *ctx; + struct pt_regs *regs; + unsigned long flags, dummy_flags; + unsigned long ovfl_regs; + unsigned int reason; + int ret; + + ctx = PFM_GET_CTX(current); + if (ctx == NULL) { + printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid); + return; + } + + PROTECT_CTX(ctx, flags); + + PFM_SET_WORK_PENDING(current, 0); + + pfm_clear_task_notify(); + + regs = task_pt_regs(current); + + /* + * extract reason for being here and clear + */ + reason = ctx->ctx_fl_trap_reason; + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE; + ovfl_regs = ctx->ctx_ovfl_regs[0]; + + DPRINT(("reason=%d state=%d\n", reason, ctx->ctx_state)); + + /* + * must be done before we check for simple-reset mode + */ + if (ctx->ctx_fl_going_zombie || ctx->ctx_state == PFM_CTX_ZOMBIE) goto do_zombie; + + + //if (CTX_OVFL_NOBLOCK(ctx)) goto skip_blocking; + if (reason == PFM_TRAP_REASON_RESET) goto skip_blocking; + + /* + * restore interrupt mask to what it was on entry. + * Could be enabled/diasbled. + */ + UNPROTECT_CTX(ctx, flags); + + /* + * force interrupt enable because of down_interruptible() + */ + local_irq_enable(); + + DPRINT(("before block sleeping\n")); + + /* + * may go through without blocking on SMP systems + * if restart has been received already by the time we call down() + */ + ret = wait_for_completion_interruptible(&ctx->ctx_restart_done); + + DPRINT(("after block sleeping ret=%d\n", ret)); + + /* + * lock context and mask interrupts again + * We save flags into a dummy because we may have + * altered interrupts mask compared to entry in this + * function. + */ + PROTECT_CTX(ctx, dummy_flags); + + /* + * we need to read the ovfl_regs only after wake-up + * because we may have had pfm_write_pmds() in between + * and that can changed PMD values and therefore + * ovfl_regs is reset for these new PMD values. + */ + ovfl_regs = ctx->ctx_ovfl_regs[0]; + + if (ctx->ctx_fl_going_zombie) { +do_zombie: + DPRINT(("context is zombie, bailing out\n")); + pfm_context_force_terminate(ctx, regs); + goto nothing_to_do; + } + /* + * in case of interruption of down() we don't restart anything + */ + if (ret < 0) goto nothing_to_do; + +skip_blocking: + pfm_resume_after_ovfl(ctx, ovfl_regs, regs); + ctx->ctx_ovfl_regs[0] = 0UL; + +nothing_to_do: + /* + * restore flags as they were upon entry + */ + UNPROTECT_CTX(ctx, flags); +} + +static int +pfm_notify_user(pfm_context_t *ctx, pfm_msg_t *msg) +{ + if (ctx->ctx_state == PFM_CTX_ZOMBIE) { + DPRINT(("ignoring overflow notification, owner is zombie\n")); + return 0; + } + + DPRINT(("waking up somebody\n")); + + if (msg) wake_up_interruptible(&ctx->ctx_msgq_wait); + + /* + * safe, we are not in intr handler, nor in ctxsw when + * we come here + */ + kill_fasync (&ctx->ctx_async_queue, SIGIO, POLL_IN); + + return 0; +} + +static int +pfm_ovfl_notify_user(pfm_context_t *ctx, unsigned long ovfl_pmds) +{ + pfm_msg_t *msg = NULL; + + if (ctx->ctx_fl_no_msg == 0) { + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_ovfl_notify_user no more notification msgs\n"); + return -1; + } + + msg->pfm_ovfl_msg.msg_type = PFM_MSG_OVFL; + msg->pfm_ovfl_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_active_set = 0; + msg->pfm_ovfl_msg.msg_ovfl_pmds[0] = ovfl_pmds; + msg->pfm_ovfl_msg.msg_ovfl_pmds[1] = 0UL; + msg->pfm_ovfl_msg.msg_ovfl_pmds[2] = 0UL; + msg->pfm_ovfl_msg.msg_ovfl_pmds[3] = 0UL; + msg->pfm_ovfl_msg.msg_tstamp = 0UL; + } + + DPRINT(("ovfl msg: msg=%p no_msg=%d fd=%d ovfl_pmds=0x%lx\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd, + ovfl_pmds)); + + return pfm_notify_user(ctx, msg); +} + +static int +pfm_end_notify_user(pfm_context_t *ctx) +{ + pfm_msg_t *msg; + + msg = pfm_get_new_msg(ctx); + if (msg == NULL) { + printk(KERN_ERR "perfmon: pfm_end_notify_user no more notification msgs\n"); + return -1; + } + /* no leak */ + memset(msg, 0, sizeof(*msg)); + + msg->pfm_end_msg.msg_type = PFM_MSG_END; + msg->pfm_end_msg.msg_ctx_fd = ctx->ctx_fd; + msg->pfm_ovfl_msg.msg_tstamp = 0UL; + + DPRINT(("end msg: msg=%p no_msg=%d ctx_fd=%d\n", + msg, + ctx->ctx_fl_no_msg, + ctx->ctx_fd)); + + return pfm_notify_user(ctx, msg); +} + +/* + * main overflow processing routine. + * it can be called from the interrupt path or explicitely during the context switch code + */ +static void +pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +{ + pfm_ovfl_arg_t *ovfl_arg; + unsigned long mask; + unsigned long old_val, ovfl_val, new_val; + unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL, smpl_pmds = 0UL, reset_pmds; + unsigned long tstamp; + pfm_ovfl_ctrl_t ovfl_ctrl; + unsigned int i, has_smpl; + int must_notify = 0; + + if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) goto stop_monitoring; + + /* + * sanity test. Should never happen + */ + if (unlikely((pmc0 & 0x1) == 0)) goto sanity_check; + + tstamp = ia64_get_itc(); + mask = pmc0 >> PMU_FIRST_COUNTER; + ovfl_val = pmu_conf->ovfl_val; + has_smpl = CTX_HAS_SMPL(ctx); + + DPRINT_ovfl(("pmc0=0x%lx pid=%d iip=0x%lx, %s " + "used_pmds=0x%lx\n", + pmc0, + task ? task->pid: -1, + (regs ? regs->cr_iip : 0), + CTX_OVFL_NOBLOCK(ctx) ? "nonblocking" : "blocking", + ctx->ctx_used_pmds[0])); + + + /* + * first we update the virtual counters + * assume there was a prior ia64_srlz_d() issued + */ + for (i = PMU_FIRST_COUNTER; mask ; i++, mask >>= 1) { + + /* skip pmd which did not overflow */ + if ((mask & 0x1) == 0) continue; + + /* + * Note that the pmd is not necessarily 0 at this point as qualified events + * may have happened before the PMU was frozen. The residual count is not + * taken into consideration here but will be with any read of the pmd via + * pfm_read_pmds(). + */ + old_val = new_val = ctx->ctx_pmds[i].val; + new_val += 1 + ovfl_val; + ctx->ctx_pmds[i].val = new_val; + + /* + * check for overflow condition + */ + if (likely(old_val > new_val)) { + ovfl_pmds |= 1UL << i; + if (PMC_OVFL_NOTIFY(ctx, i)) ovfl_notify |= 1UL << i; + } + + DPRINT_ovfl(("ctx_pmd[%d].val=0x%lx old_val=0x%lx pmd=0x%lx ovfl_pmds=0x%lx ovfl_notify=0x%lx\n", + i, + new_val, + old_val, + ia64_get_pmd(i) & ovfl_val, + ovfl_pmds, + ovfl_notify)); + } + + /* + * there was no 64-bit overflow, nothing else to do + */ + if (ovfl_pmds == 0UL) return; + + /* + * reset all control bits + */ + ovfl_ctrl.val = 0; + reset_pmds = 0UL; + + /* + * if a sampling format module exists, then we "cache" the overflow by + * calling the module's handler() routine. + */ + if (has_smpl) { + unsigned long start_cycles, end_cycles; + unsigned long pmd_mask; + int j, k, ret = 0; + int this_cpu = smp_processor_id(); + + pmd_mask = ovfl_pmds >> PMU_FIRST_COUNTER; + ovfl_arg = &ctx->ctx_ovfl_arg; + + prefetch(ctx->ctx_smpl_hdr); + + for(i=PMU_FIRST_COUNTER; pmd_mask && ret == 0; i++, pmd_mask >>=1) { + + mask = 1UL << i; + + if ((pmd_mask & 0x1) == 0) continue; + + ovfl_arg->ovfl_pmd = (unsigned char )i; + ovfl_arg->ovfl_notify = ovfl_notify & mask ? 1 : 0; + ovfl_arg->active_set = 0; + ovfl_arg->ovfl_ctrl.val = 0; /* module must fill in all fields */ + ovfl_arg->smpl_pmds[0] = smpl_pmds = ctx->ctx_pmds[i].smpl_pmds[0]; + + ovfl_arg->pmd_value = ctx->ctx_pmds[i].val; + ovfl_arg->pmd_last_reset = ctx->ctx_pmds[i].lval; + ovfl_arg->pmd_eventid = ctx->ctx_pmds[i].eventid; + + /* + * copy values of pmds of interest. Sampling format may copy them + * into sampling buffer. + */ + if (smpl_pmds) { + for(j=0, k=0; smpl_pmds; j++, smpl_pmds >>=1) { + if ((smpl_pmds & 0x1) == 0) continue; + ovfl_arg->smpl_pmds_values[k++] = PMD_IS_COUNTING(j) ? pfm_read_soft_counter(ctx, j) : ia64_get_pmd(j); + DPRINT_ovfl(("smpl_pmd[%d]=pmd%u=0x%lx\n", k-1, j, ovfl_arg->smpl_pmds_values[k-1])); + } + } + + pfm_stats[this_cpu].pfm_smpl_handler_calls++; + + start_cycles = ia64_get_itc(); + + /* + * call custom buffer format record (handler) routine + */ + ret = (*ctx->ctx_buf_fmt->fmt_handler)(task, ctx->ctx_smpl_hdr, ovfl_arg, regs, tstamp); + + end_cycles = ia64_get_itc(); + + /* + * For those controls, we take the union because they have + * an all or nothing behavior. + */ + ovfl_ctrl.bits.notify_user |= ovfl_arg->ovfl_ctrl.bits.notify_user; + ovfl_ctrl.bits.block_task |= ovfl_arg->ovfl_ctrl.bits.block_task; + ovfl_ctrl.bits.mask_monitoring |= ovfl_arg->ovfl_ctrl.bits.mask_monitoring; + /* + * build the bitmask of pmds to reset now + */ + if (ovfl_arg->ovfl_ctrl.bits.reset_ovfl_pmds) reset_pmds |= mask; + + pfm_stats[this_cpu].pfm_smpl_handler_cycles += end_cycles - start_cycles; + } + /* + * when the module cannot handle the rest of the overflows, we abort right here + */ + if (ret && pmd_mask) { + DPRINT(("handler aborts leftover ovfl_pmds=0x%lx\n", + pmd_mask<ctx_ovfl_regs[0] = ovfl_pmds; + + /* + * check for blocking context + */ + if (CTX_OVFL_NOBLOCK(ctx) == 0 && ovfl_ctrl.bits.block_task) { + + ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCK; + + /* + * set the perfmon specific checking pending work for the task + */ + PFM_SET_WORK_PENDING(task, 1); + + /* + * when coming from ctxsw, current still points to the + * previous task, therefore we must work with task and not current. + */ + pfm_set_task_notify(task); + } + /* + * defer until state is changed (shorten spin window). the context is locked + * anyway, so the signal receiver would come spin for nothing. + */ + must_notify = 1; + } + + DPRINT_ovfl(("owner [%d] pending=%ld reason=%u ovfl_pmds=0x%lx ovfl_notify=0x%lx masked=%d\n", + GET_PMU_OWNER() ? GET_PMU_OWNER()->pid : -1, + PFM_GET_WORK_PENDING(task), + ctx->ctx_fl_trap_reason, + ovfl_pmds, + ovfl_notify, + ovfl_ctrl.bits.mask_monitoring ? 1 : 0)); + /* + * in case monitoring must be stopped, we toggle the psr bits + */ + if (ovfl_ctrl.bits.mask_monitoring) { + pfm_mask_monitoring(task); + ctx->ctx_state = PFM_CTX_MASKED; + ctx->ctx_fl_can_restart = 1; + } + + /* + * send notification now + */ + if (must_notify) pfm_ovfl_notify_user(ctx, ovfl_notify); + + return; + +sanity_check: + printk(KERN_ERR "perfmon: CPU%d overflow handler [%d] pmc0=0x%lx\n", + smp_processor_id(), + task ? task->pid : -1, + pmc0); + return; + +stop_monitoring: + /* + * in SMP, zombie context is never restored but reclaimed in pfm_load_regs(). + * Moreover, zombies are also reclaimed in pfm_save_regs(). Therefore we can + * come here as zombie only if the task is the current task. In which case, we + * can access the PMU hardware directly. + * + * Note that zombies do have PM_VALID set. So here we do the minimal. + * + * In case the context was zombified it could not be reclaimed at the time + * the monitoring program exited. At this point, the PMU reservation has been + * returned, the sampiing buffer has been freed. We must convert this call + * into a spurious interrupt. However, we must also avoid infinite overflows + * by stopping monitoring for this task. We can only come here for a per-task + * context. All we need to do is to stop monitoring using the psr bits which + * are always task private. By re-enabling secure montioring, we ensure that + * the monitored task will not be able to re-activate monitoring. + * The task will eventually be context switched out, at which point the context + * will be reclaimed (that includes releasing ownership of the PMU). + * + * So there might be a window of time where the number of per-task session is zero + * yet one PMU might have a owner and get at most one overflow interrupt for a zombie + * context. This is safe because if a per-task session comes in, it will push this one + * out and by the virtue on pfm_save_regs(), this one will disappear. If a system wide + * session is force on that CPU, given that we use task pinning, pfm_save_regs() will + * also push our zombie context out. + * + * Overall pretty hairy stuff.... + */ + DPRINT(("ctx is zombie for [%d], converted to spurious\n", task ? task->pid: -1)); + pfm_clear_psr_up(); + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + return; +} + +static int +pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + struct task_struct *task; + pfm_context_t *ctx; + unsigned long flags; + u64 pmc0; + int this_cpu = smp_processor_id(); + int retval = 0; + + pfm_stats[this_cpu].pfm_ovfl_intr_count++; + + /* + * srlz.d done before arriving here + */ + pmc0 = ia64_get_pmc(0); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + /* + * if we have some pending bits set + * assumes : if any PMC0.bit[63-1] is set, then PMC0.fr = 1 + */ + if (PMC0_HAS_OVFL(pmc0) && task) { + /* + * we assume that pmc0.fr is always set here + */ + + /* sanity check */ + if (!ctx) goto report_spurious1; + + if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) + goto report_spurious2; + + PROTECT_CTX_NOPRINT(ctx, flags); + + pfm_overflow_handler(task, ctx, pmc0, regs); + + UNPROTECT_CTX_NOPRINT(ctx, flags); + + } else { + pfm_stats[this_cpu].pfm_spurious_ovfl_intr_count++; + retval = -1; + } + /* + * keep it unfrozen at all times + */ + pfm_unfreeze_pmu(); + + return retval; + +report_spurious1: + printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n", + this_cpu, task->pid); + pfm_unfreeze_pmu(); + return -1; +report_spurious2: + printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d, invalid flag\n", + this_cpu, + task->pid); + pfm_unfreeze_pmu(); + return -1; +} + +static irqreturn_t +pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) +{ + unsigned long start_cycles, total_cycles; + unsigned long min, max; + int this_cpu; + int ret; + + this_cpu = get_cpu(); + if (likely(!pfm_alt_intr_handler)) { + min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; + max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; + + start_cycles = ia64_get_itc(); + + ret = pfm_do_interrupt_handler(irq, arg, regs); + + total_cycles = ia64_get_itc(); + + /* + * don't measure spurious interrupts + */ + if (likely(ret == 0)) { + total_cycles -= start_cycles; + + if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles; + if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles; + + pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles; + } + } + else { + (*pfm_alt_intr_handler->handler)(irq, arg, regs); + } + + put_cpu_no_resched(); + return IRQ_HANDLED; +} + +/* + * /proc/perfmon interface, for debug only + */ + +#define PFM_PROC_SHOW_HEADER ((void *)NR_CPUS+1) + +static void * +pfm_proc_start(struct seq_file *m, loff_t *pos) +{ + if (*pos == 0) { + return PFM_PROC_SHOW_HEADER; + } + + while (*pos <= NR_CPUS) { + if (cpu_online(*pos - 1)) { + return (void *)*pos; + } + ++*pos; + } + return NULL; +} + +static void * +pfm_proc_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return pfm_proc_start(m, pos); +} + +static void +pfm_proc_stop(struct seq_file *m, void *v) +{ +} + +static void +pfm_proc_show_header(struct seq_file *m) +{ + struct list_head * pos; + pfm_buffer_fmt_t * entry; + unsigned long flags; + + seq_printf(m, + "perfmon version : %u.%u\n" + "model : %s\n" + "fastctxsw : %s\n" + "expert mode : %s\n" + "ovfl_mask : 0x%lx\n" + "PMU flags : 0x%x\n", + PFM_VERSION_MAJ, PFM_VERSION_MIN, + pmu_conf->pmu_name, + pfm_sysctl.fastctxsw > 0 ? "Yes": "No", + pfm_sysctl.expert_mode > 0 ? "Yes": "No", + pmu_conf->ovfl_val, + pmu_conf->flags); + + LOCK_PFS(flags); + + seq_printf(m, + "proc_sessions : %u\n" + "sys_sessions : %u\n" + "sys_use_dbregs : %u\n" + "ptrace_use_dbregs : %u\n", + pfm_sessions.pfs_task_sessions, + pfm_sessions.pfs_sys_sessions, + pfm_sessions.pfs_sys_use_dbregs, + pfm_sessions.pfs_ptrace_use_dbregs); + + UNLOCK_PFS(flags); + + spin_lock(&pfm_buffer_fmt_lock); + + list_for_each(pos, &pfm_buffer_fmt_list) { + entry = list_entry(pos, pfm_buffer_fmt_t, fmt_list); + seq_printf(m, "format : %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x %s\n", + entry->fmt_uuid[0], + entry->fmt_uuid[1], + entry->fmt_uuid[2], + entry->fmt_uuid[3], + entry->fmt_uuid[4], + entry->fmt_uuid[5], + entry->fmt_uuid[6], + entry->fmt_uuid[7], + entry->fmt_uuid[8], + entry->fmt_uuid[9], + entry->fmt_uuid[10], + entry->fmt_uuid[11], + entry->fmt_uuid[12], + entry->fmt_uuid[13], + entry->fmt_uuid[14], + entry->fmt_uuid[15], + entry->fmt_name); + } + spin_unlock(&pfm_buffer_fmt_lock); + +} + +static int +pfm_proc_show(struct seq_file *m, void *v) +{ + unsigned long psr; + unsigned int i; + int cpu; + + if (v == PFM_PROC_SHOW_HEADER) { + pfm_proc_show_header(m); + return 0; + } + + /* show info for CPU (v - 1) */ + + cpu = (long)v - 1; + seq_printf(m, + "CPU%-2d overflow intrs : %lu\n" + "CPU%-2d overflow cycles : %lu\n" + "CPU%-2d overflow min : %lu\n" + "CPU%-2d overflow max : %lu\n" + "CPU%-2d smpl handler calls : %lu\n" + "CPU%-2d smpl handler cycles : %lu\n" + "CPU%-2d spurious intrs : %lu\n" + "CPU%-2d replay intrs : %lu\n" + "CPU%-2d syst_wide : %d\n" + "CPU%-2d dcr_pp : %d\n" + "CPU%-2d exclude idle : %d\n" + "CPU%-2d owner : %d\n" + "CPU%-2d context : %p\n" + "CPU%-2d activations : %lu\n", + cpu, pfm_stats[cpu].pfm_ovfl_intr_count, + cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles, + cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles_min, + cpu, pfm_stats[cpu].pfm_ovfl_intr_cycles_max, + cpu, pfm_stats[cpu].pfm_smpl_handler_calls, + cpu, pfm_stats[cpu].pfm_smpl_handler_cycles, + cpu, pfm_stats[cpu].pfm_spurious_ovfl_intr_count, + cpu, pfm_stats[cpu].pfm_replay_ovfl_intr_count, + cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_SYST_WIDE ? 1 : 0, + cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_DCR_PP ? 1 : 0, + cpu, pfm_get_cpu_data(pfm_syst_info, cpu) & PFM_CPUINFO_EXCL_IDLE ? 1 : 0, + cpu, pfm_get_cpu_data(pmu_owner, cpu) ? pfm_get_cpu_data(pmu_owner, cpu)->pid: -1, + cpu, pfm_get_cpu_data(pmu_ctx, cpu), + cpu, pfm_get_cpu_data(pmu_activation_number, cpu)); + + if (num_online_cpus() == 1 && pfm_sysctl.debug > 0) { + + psr = pfm_get_psr(); + + ia64_srlz_d(); + + seq_printf(m, + "CPU%-2d psr : 0x%lx\n" + "CPU%-2d pmc0 : 0x%lx\n", + cpu, psr, + cpu, ia64_get_pmc(0)); + + for (i=0; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_COUNTING(i) == 0) continue; + seq_printf(m, + "CPU%-2d pmc%u : 0x%lx\n" + "CPU%-2d pmd%u : 0x%lx\n", + cpu, i, ia64_get_pmc(i), + cpu, i, ia64_get_pmd(i)); + } + } + return 0; +} + +struct seq_operations pfm_seq_ops = { + .start = pfm_proc_start, + .next = pfm_proc_next, + .stop = pfm_proc_stop, + .show = pfm_proc_show +}; + +static int +pfm_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &pfm_seq_ops); +} + + +/* + * we come here as soon as local_cpu_data->pfm_syst_wide is set. this happens + * during pfm_enable() hence before pfm_start(). We cannot assume monitoring + * is active or inactive based on mode. We must rely on the value in + * local_cpu_data->pfm_syst_info + */ +void +pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_ctxswin) +{ + struct pt_regs *regs; + unsigned long dcr; + unsigned long dcr_pp; + + dcr_pp = info & PFM_CPUINFO_DCR_PP ? 1 : 0; + + /* + * pid 0 is guaranteed to be the idle task. There is one such task with pid 0 + * on every CPU, so we can rely on the pid to identify the idle task. + */ + if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) { + regs = task_pt_regs(task); + ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0; + return; + } + /* + * if monitoring has started + */ + if (dcr_pp) { + dcr = ia64_getreg(_IA64_REG_CR_DCR); + /* + * context switching in? + */ + if (is_ctxswin) { + /* mask monitoring for the idle task */ + ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP); + pfm_clear_psr_pp(); + ia64_srlz_i(); + return; + } + /* + * context switching out + * restore monitoring for next task + * + * Due to inlining this odd if-then-else construction generates + * better code. + */ + ia64_setreg(_IA64_REG_CR_DCR, dcr |IA64_DCR_PP); + pfm_set_psr_pp(); + ia64_srlz_i(); + } +} + +#ifdef CONFIG_SMP + +static void +pfm_force_cleanup(pfm_context_t *ctx, struct pt_regs *regs) +{ + struct task_struct *task = ctx->ctx_task; + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->sp = 1; + + if (GET_PMU_OWNER() == task) { + DPRINT(("cleared ownership for [%d]\n", ctx->ctx_task->pid)); + SET_PMU_OWNER(NULL, NULL); + } + + /* + * disconnect the task from the context and vice-versa + */ + PFM_SET_WORK_PENDING(task, 0); + + task->thread.pfm_context = NULL; + task->thread.flags &= ~IA64_THREAD_PM_VALID; + + DPRINT(("force cleanup for [%d]\n", task->pid)); +} + + +/* + * in 2.6, interrupts are masked when we come here and the runqueue lock is held + */ +void +pfm_save_regs(struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + u64 psr; + + + ctx = PFM_GET_CTX(task); + if (ctx == NULL) return; + t = &task->thread; + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + + if (ctx->ctx_state == PFM_CTX_ZOMBIE) { + struct pt_regs *regs = task_pt_regs(task); + + pfm_clear_psr_up(); + + pfm_force_cleanup(ctx, regs); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + pfm_context_free(ctx); + return; + } + + /* + * save current PSR: needed because we modify it + */ + ia64_srlz_d(); + psr = pfm_get_psr(); + + BUG_ON(psr & (IA64_PSR_I)); + + /* + * stop monitoring: + * This is the last instruction which may generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level + */ + pfm_clear_psr_up(); + + /* + * keep a copy of psr.up (for reload) + */ + ctx->ctx_saved_psr_up = psr & IA64_PSR_UP; + + /* + * release ownership of this PMU. + * PM interrupts are masked, so nothing + * can happen. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * we systematically save the PMD as we have no + * guarantee we will be schedule at that same + * CPU again. + */ + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); + + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * we will need it on the restore path to check + * for pending overflow. + */ + t->pmcs[0] = ia64_get_pmc(0); + + /* + * unfreeze PMU if had pending overflows + */ + if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu(); + + /* + * finally, allow context access. + * interrupts will still be masked after this call. + */ + pfm_unprotect_ctx_ctxsw(ctx, flags); +} + +#else /* !CONFIG_SMP */ +void +pfm_save_regs(struct task_struct *task) +{ + pfm_context_t *ctx; + u64 psr; + + ctx = PFM_GET_CTX(task); + if (ctx == NULL) return; + + /* + * save current PSR: needed because we modify it + */ + psr = pfm_get_psr(); + + BUG_ON(psr & (IA64_PSR_I)); + + /* + * stop monitoring: + * This is the last instruction which may generate an overflow + * + * We do not need to set psr.sp because, it is irrelevant in kernel. + * It will be restored from ipsr when going back to user level + */ + pfm_clear_psr_up(); + + /* + * keep a copy of psr.up (for reload) + */ + ctx->ctx_saved_psr_up = psr & IA64_PSR_UP; +} + +static void +pfm_lazy_save_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long flags; + + { u64 psr = pfm_get_psr(); + BUG_ON(psr & IA64_PSR_UP); + } + + ctx = PFM_GET_CTX(task); + t = &task->thread; + + /* + * we need to mask PMU overflow here to + * make sure that we maintain pmc0 until + * we save it. overflow interrupts are + * treated as spurious if there is no + * owner. + * + * XXX: I don't think this is necessary + */ + PROTECT_CTX(ctx,flags); + + /* + * release ownership of this PMU. + * must be done before we save the registers. + * + * after this call any PMU interrupt is treated + * as spurious. + */ + SET_PMU_OWNER(NULL, NULL); + + /* + * save all the pmds we use + */ + pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]); + + /* + * save pmc0 ia64_srlz_d() done in pfm_save_pmds() + * it is needed to check for pended overflow + * on the restore path + */ + t->pmcs[0] = ia64_get_pmc(0); + + /* + * unfreeze PMU if had pending overflows + */ + if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu(); + + /* + * now get can unmask PMU interrupts, they will + * be treated as purely spurious and we will not + * lose any information + */ + UNPROTECT_CTX(ctx,flags); +} +#endif /* CONFIG_SMP */ + +#ifdef CONFIG_SMP +/* + * in 2.6, interrupts are masked when we come here and the runqueue lock is held + */ +void +pfm_load_regs (struct task_struct *task) +{ + pfm_context_t *ctx; + struct thread_struct *t; + unsigned long pmc_mask = 0UL, pmd_mask = 0UL; + unsigned long flags; + u64 psr, psr_up; + int need_irq_resend; + + ctx = PFM_GET_CTX(task); + if (unlikely(ctx == NULL)) return; + + BUG_ON(GET_PMU_OWNER()); + + t = &task->thread; + /* + * possible on unload + */ + if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) return; + + /* + * we always come here with interrupts ALREADY disabled by + * the scheduler. So we simply need to protect against concurrent + * access, not CPU concurrency. + */ + flags = pfm_protect_ctx_ctxsw(ctx); + psr = pfm_get_psr(); + + need_irq_resend = pmu_conf->flags & PFM_PMU_IRQ_RESEND; + + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + BUG_ON(psr & IA64_PSR_I); + + if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) { + struct pt_regs *regs = task_pt_regs(task); + + BUG_ON(ctx->ctx_smpl_hdr); + + pfm_force_cleanup(ctx, regs); + + pfm_unprotect_ctx_ctxsw(ctx, flags); + + /* + * this one (kmalloc'ed) is fine with interrupts disabled + */ + pfm_context_free(ctx); + + return; + } + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + /* + * retrieve saved psr.up + */ + psr_up = ctx->ctx_saved_psr_up; + + /* + * if we were the last user of the PMU on that CPU, + * then nothing to do except restore psr + */ + if (GET_LAST_CPU(ctx) == smp_processor_id() && ctx->ctx_last_activation == GET_ACTIVATION()) { + + /* + * retrieve partial reload masks (due to user modifications) + */ + pmc_mask = ctx->ctx_reload_pmcs[0]; + pmd_mask = ctx->ctx_reload_pmds[0]; + + } else { + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately. + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + } + /* + * when context is MASKED, we will restore PMC with plm=0 + * and PMD with stale information, but that's ok, nothing + * will be captured. + * + * XXX: optimize here + */ + if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask); + if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask); + + /* + * check for pending overflow at the time the state + * was saved. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + /* + * reload pmc0 with the overflow information + * On McKinley PMU, this will trigger a PMU interrupt + */ + ia64_set_pmc(0, t->pmcs[0]); + ia64_srlz_d(); + t->pmcs[0] = 0UL; + + /* + * will replay the PMU interrupt + */ + if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR); + + pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++; + } + + /* + * we just did a reload, so we reset the partial reload fields + */ + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + SET_LAST_CPU(ctx, smp_processor_id()); + + /* + * dump activation value for this PMU + */ + INC_ACTIVATION(); + /* + * record current activation for this context + */ + SET_ACTIVATION(ctx); + + /* + * establish new ownership. + */ + SET_PMU_OWNER(task, ctx); + + /* + * restore the psr.up bit. measurement + * is active again. + * no PMU interrupt can happen at this point + * because we still have interrupts disabled. + */ + if (likely(psr_up)) pfm_set_psr_up(); + + /* + * allow concurrent access to context + */ + pfm_unprotect_ctx_ctxsw(ctx, flags); +} +#else /* !CONFIG_SMP */ +/* + * reload PMU state for UP kernels + * in 2.5 we come here with interrupts disabled + */ +void +pfm_load_regs (struct task_struct *task) +{ + struct thread_struct *t; + pfm_context_t *ctx; + struct task_struct *owner; + unsigned long pmd_mask, pmc_mask; + u64 psr, psr_up; + int need_irq_resend; + + owner = GET_PMU_OWNER(); + ctx = PFM_GET_CTX(task); + t = &task->thread; + psr = pfm_get_psr(); + + BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP)); + BUG_ON(psr & IA64_PSR_I); + + /* + * we restore ALL the debug registers to avoid picking up + * stale state. + * + * This must be done even when the task is still the owner + * as the registers may have been modified via ptrace() + * (not perfmon) by the previous task. + */ + if (ctx->ctx_fl_using_dbreg) { + pfm_restore_ibrs(ctx->ctx_ibrs, pmu_conf->num_ibrs); + pfm_restore_dbrs(ctx->ctx_dbrs, pmu_conf->num_dbrs); + } + + /* + * retrieved saved psr.up + */ + psr_up = ctx->ctx_saved_psr_up; + need_irq_resend = pmu_conf->flags & PFM_PMU_IRQ_RESEND; + + /* + * short path, our state is still there, just + * need to restore psr and we go + * + * we do not touch either PMC nor PMD. the psr is not touched + * by the overflow_handler. So we are safe w.r.t. to interrupt + * concurrency even without interrupt masking. + */ + if (likely(owner == task)) { + if (likely(psr_up)) pfm_set_psr_up(); + return; + } + + /* + * someone else is still using the PMU, first push it out and + * then we'll be able to install our stuff ! + * + * Upon return, there will be no owner for the current PMU + */ + if (owner) pfm_lazy_save_regs(owner); + + /* + * To avoid leaking information to the user level when psr.sp=0, + * we must reload ALL implemented pmds (even the ones we don't use). + * In the kernel we only allow PFM_READ_PMDS on registers which + * we initialized or requested (sampling) so there is no risk there. + */ + pmd_mask = pfm_sysctl.fastctxsw ? ctx->ctx_used_pmds[0] : ctx->ctx_all_pmds[0]; + + /* + * ALL accessible PMCs are systematically reloaded, unused registers + * get their default (from pfm_reset_pmu_state()) values to avoid picking + * up stale configuration. + * + * PMC0 is never in the mask. It is always restored separately + */ + pmc_mask = ctx->ctx_all_pmcs[0]; + + pfm_restore_pmds(t->pmds, pmd_mask); + pfm_restore_pmcs(t->pmcs, pmc_mask); + + /* + * check for pending overflow at the time the state + * was saved. + */ + if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) { + /* + * reload pmc0 with the overflow information + * On McKinley PMU, this will trigger a PMU interrupt + */ + ia64_set_pmc(0, t->pmcs[0]); + ia64_srlz_d(); + + t->pmcs[0] = 0UL; + + /* + * will replay the PMU interrupt + */ + if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR); + + pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++; + } + + /* + * establish new ownership. + */ + SET_PMU_OWNER(task, ctx); + + /* + * restore the psr.up bit. measurement + * is active again. + * no PMU interrupt can happen at this point + * because we still have interrupts disabled. + */ + if (likely(psr_up)) pfm_set_psr_up(); +} +#endif /* CONFIG_SMP */ + +/* + * this function assumes monitoring is stopped + */ +static void +pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) +{ + u64 pmc0; + unsigned long mask2, val, pmd_val, ovfl_val; + int i, can_access_pmu = 0; + int is_self; + + /* + * is the caller the task being monitored (or which initiated the + * session for system wide measurements) + */ + is_self = ctx->ctx_task == task ? 1 : 0; + + /* + * can access PMU is task is the owner of the PMU state on the current CPU + * or if we are running on the CPU bound to the context in system-wide mode + * (that is not necessarily the task the context is attached to in this mode). + * In system-wide we always have can_access_pmu true because a task running on an + * invalid processor is flagged earlier in the call stack (see pfm_stop). + */ + can_access_pmu = (GET_PMU_OWNER() == task) || (ctx->ctx_fl_system && ctx->ctx_cpu == smp_processor_id()); + if (can_access_pmu) { + /* + * Mark the PMU as not owned + * This will cause the interrupt handler to do nothing in case an overflow + * interrupt was in-flight + * This also guarantees that pmc0 will contain the final state + * It virtually gives us full control on overflow processing from that point + * on. + */ + SET_PMU_OWNER(NULL, NULL); + DPRINT(("releasing ownership\n")); + + /* + * read current overflow status: + * + * we are guaranteed to read the final stable state + */ + ia64_srlz_d(); + pmc0 = ia64_get_pmc(0); /* slow */ + + /* + * reset freeze bit, overflow status information destroyed + */ + pfm_unfreeze_pmu(); + } else { + pmc0 = task->thread.pmcs[0]; + /* + * clear whatever overflow status bits there were + */ + task->thread.pmcs[0] = 0; + } + ovfl_val = pmu_conf->ovfl_val; + /* + * we save all the used pmds + * we take care of overflows for counting PMDs + * + * XXX: sampling situation is not taken into account here + */ + mask2 = ctx->ctx_used_pmds[0]; + + DPRINT(("is_self=%d ovfl_val=0x%lx mask2=0x%lx\n", is_self, ovfl_val, mask2)); + + for (i = 0; mask2; i++, mask2>>=1) { + + /* skip non used pmds */ + if ((mask2 & 0x1) == 0) continue; + + /* + * can access PMU always true in system wide mode + */ + val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i]; + + if (PMD_IS_COUNTING(i)) { + DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n", + task->pid, + i, + ctx->ctx_pmds[i].val, + val & ovfl_val)); + + /* + * we rebuild the full 64 bit value of the counter + */ + val = ctx->ctx_pmds[i].val + (val & ovfl_val); + + /* + * now everything is in ctx_pmds[] and we need + * to clear the saved context from save_regs() such that + * pfm_read_pmds() gets the correct value + */ + pmd_val = 0UL; + + /* + * take care of overflow inline + */ + if (pmc0 & (1UL << i)) { + val += 1 + ovfl_val; + DPRINT(("[%d] pmd[%d] overflowed\n", task->pid, i)); + } + } + + DPRINT(("[%d] ctx_pmd[%d]=0x%lx pmd_val=0x%lx\n", task->pid, i, val, pmd_val)); + + if (is_self) task->thread.pmds[i] = pmd_val; + + ctx->ctx_pmds[i].val = val; + } +} + +static struct irqaction perfmon_irqaction = { + .handler = pfm_interrupt_handler, + .flags = SA_INTERRUPT, + .name = "perfmon" +}; + +static void +pfm_alt_save_pmu_state(void *data) +{ + struct pt_regs *regs; + + regs = task_pt_regs(current); + + DPRINT(("called\n")); + + /* + * should not be necessary but + * let's take not risk + */ + pfm_clear_psr_up(); + pfm_clear_psr_pp(); + ia64_psr(regs)->pp = 0; + + /* + * This call is required + * May cause a spurious interrupt on some processors + */ + pfm_freeze_pmu(); + + ia64_srlz_d(); +} + +void +pfm_alt_restore_pmu_state(void *data) +{ + struct pt_regs *regs; + + regs = task_pt_regs(current); + + DPRINT(("called\n")); + + /* + * put PMU back in state expected + * by perfmon + */ + pfm_clear_psr_up(); + pfm_clear_psr_pp(); + ia64_psr(regs)->pp = 0; + + /* + * perfmon runs with PMU unfrozen at all times + */ + pfm_unfreeze_pmu(); + + ia64_srlz_d(); +} + +int +pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) +{ + int ret, i; + int reserve_cpu; + + /* some sanity checks */ + if (hdl == NULL || hdl->handler == NULL) return -EINVAL; + + /* do the easy test first */ + if (pfm_alt_intr_handler) return -EBUSY; + + /* one at a time in the install or remove, just fail the others */ + if (!spin_trylock(&pfm_alt_install_check)) { + return -EBUSY; + } + + /* reserve our session */ + for_each_online_cpu(reserve_cpu) { + ret = pfm_reserve_session(NULL, 1, reserve_cpu); + if (ret) goto cleanup_reserve; + } + + /* save the current system wide pmu states */ + ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 0, 1); + if (ret) { + DPRINT(("on_each_cpu() failed: %d\n", ret)); + goto cleanup_reserve; + } + + /* officially change to the alternate interrupt handler */ + pfm_alt_intr_handler = hdl; + + spin_unlock(&pfm_alt_install_check); + + return 0; + +cleanup_reserve: + for_each_online_cpu(i) { + /* don't unreserve more than we reserved */ + if (i >= reserve_cpu) break; + + pfm_unreserve_session(NULL, 1, i); + } + + spin_unlock(&pfm_alt_install_check); + + return ret; +} +EXPORT_SYMBOL_GPL(pfm_install_alt_pmu_interrupt); + +int +pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) +{ + int i; + int ret; + + if (hdl == NULL) return -EINVAL; + + /* cannot remove someone else's handler! */ + if (pfm_alt_intr_handler != hdl) return -EINVAL; + + /* one at a time in the install or remove, just fail the others */ + if (!spin_trylock(&pfm_alt_install_check)) { + return -EBUSY; + } + + pfm_alt_intr_handler = NULL; + + ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 0, 1); + if (ret) { + DPRINT(("on_each_cpu() failed: %d\n", ret)); + } + + for_each_online_cpu(i) { + pfm_unreserve_session(NULL, 1, i); + } + + spin_unlock(&pfm_alt_install_check); + + return 0; +} +EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt); + +/* + * perfmon initialization routine, called from the initcall() table + */ +static int init_pfm_fs(void); + +static int __init +pfm_probe_pmu(void) +{ + pmu_config_t **p; + int family; + + family = local_cpu_data->family; + p = pmu_confs; + + while(*p) { + if ((*p)->probe) { + if ((*p)->probe() == 0) goto found; + } else if ((*p)->pmu_family == family || (*p)->pmu_family == 0xff) { + goto found; + } + p++; + } + return -1; +found: + pmu_conf = *p; + return 0; +} + +static struct file_operations pfm_proc_fops = { + .open = pfm_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +int __init +pfm_init(void) +{ + unsigned int n, n_counters, i; + + printk("perfmon: version %u.%u IRQ %u\n", + PFM_VERSION_MAJ, + PFM_VERSION_MIN, + IA64_PERFMON_VECTOR); + + if (pfm_probe_pmu()) { + printk(KERN_INFO "perfmon: disabled, there is no support for processor family %d\n", + local_cpu_data->family); + return -ENODEV; + } + + /* + * compute the number of implemented PMD/PMC from the + * description tables + */ + n = 0; + for (i=0; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + pmu_conf->impl_pmcs[i>>6] |= 1UL << (i&63); + n++; + } + pmu_conf->num_pmcs = n; + + n = 0; n_counters = 0; + for (i=0; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + pmu_conf->impl_pmds[i>>6] |= 1UL << (i&63); + n++; + if (PMD_IS_COUNTING(i)) n_counters++; + } + pmu_conf->num_pmds = n; + pmu_conf->num_counters = n_counters; + + /* + * sanity checks on the number of debug registers + */ + if (pmu_conf->use_rr_dbregs) { + if (pmu_conf->num_ibrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of code debug registers (%u)\n", pmu_conf->num_ibrs); + pmu_conf = NULL; + return -1; + } + if (pmu_conf->num_dbrs > IA64_NUM_DBG_REGS) { + printk(KERN_INFO "perfmon: unsupported number of data debug registers (%u)\n", pmu_conf->num_ibrs); + pmu_conf = NULL; + return -1; + } + } + + printk("perfmon: %s PMU detected, %u PMCs, %u PMDs, %u counters (%lu bits)\n", + pmu_conf->pmu_name, + pmu_conf->num_pmcs, + pmu_conf->num_pmds, + pmu_conf->num_counters, + ffz(pmu_conf->ovfl_val)); + + /* sanity check */ + if (pmu_conf->num_pmds >= IA64_NUM_PMD_REGS || pmu_conf->num_pmcs >= IA64_NUM_PMC_REGS) { + printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n"); + pmu_conf = NULL; + return -1; + } + + /* + * create /proc/perfmon (mostly for debugging purposes) + */ + perfmon_dir = create_proc_entry("perfmon", S_IRUGO, NULL); + if (perfmon_dir == NULL) { + printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n"); + pmu_conf = NULL; + return -1; + } + /* + * install customized file operations for /proc/perfmon entry + */ + perfmon_dir->proc_fops = &pfm_proc_fops; + + /* + * create /proc/sys/kernel/perfmon (for debugging purposes) + */ + pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); + + /* + * initialize all our spinlocks + */ + spin_lock_init(&pfm_sessions.pfs_lock); + spin_lock_init(&pfm_buffer_fmt_lock); + + init_pfm_fs(); + + for(i=0; i < NR_CPUS; i++) pfm_stats[i].pfm_ovfl_intr_cycles_min = ~0UL; + + return 0; +} + +__initcall(pfm_init); + +/* + * this function is called before pfm_init() + */ +void +pfm_init_percpu (void) +{ + /* + * make sure no measurement is active + * (may inherit programmed PMCs from EFI). + */ + pfm_clear_psr_pp(); + pfm_clear_psr_up(); + + /* + * we run with the PMU not frozen at all times + */ + pfm_unfreeze_pmu(); + + if (smp_processor_id() == 0) + register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction); + + ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR); + ia64_srlz_d(); +} + +/* + * used for debug purposes only + */ +void +dump_pmu_state(const char *from) +{ + struct task_struct *task; + struct thread_struct *t; + struct pt_regs *regs; + pfm_context_t *ctx; + unsigned long psr, dcr, info, flags; + int i, this_cpu; + + local_irq_save(flags); + + this_cpu = smp_processor_id(); + regs = task_pt_regs(current); + info = PFM_CPUINFO_GET(); + dcr = ia64_getreg(_IA64_REG_CR_DCR); + + if (info == 0 && ia64_psr(regs)->pp == 0 && (dcr & IA64_DCR_PP) == 0) { + local_irq_restore(flags); + return; + } + + printk("CPU%d from %s() current [%d] iip=0x%lx %s\n", + this_cpu, + from, + current->pid, + regs->cr_iip, + current->comm); + + task = GET_PMU_OWNER(); + ctx = GET_PMU_CTX(); + + printk("->CPU%d owner [%d] ctx=%p\n", this_cpu, task ? task->pid : -1, ctx); + + psr = pfm_get_psr(); + + printk("->CPU%d pmc0=0x%lx psr.pp=%d psr.up=%d dcr.pp=%d syst_info=0x%lx user_psr.up=%d user_psr.pp=%d\n", + this_cpu, + ia64_get_pmc(0), + psr & IA64_PSR_PP ? 1 : 0, + psr & IA64_PSR_UP ? 1 : 0, + dcr & IA64_DCR_PP ? 1 : 0, + info, + ia64_psr(regs)->up, + ia64_psr(regs)->pp); + + ia64_psr(regs)->up = 0; + ia64_psr(regs)->pp = 0; + + t = ¤t->thread; + + for (i=1; PMC_IS_LAST(i) == 0; i++) { + if (PMC_IS_IMPL(i) == 0) continue; + printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, t->pmcs[i]); + } + + for (i=1; PMD_IS_LAST(i) == 0; i++) { + if (PMD_IS_IMPL(i) == 0) continue; + printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, t->pmds[i]); + } + + if (ctx) { + printk("->CPU%d ctx_state=%d vaddr=%p addr=%p fd=%d ctx_task=[%d] saved_psr_up=0x%lx\n", + this_cpu, + ctx->ctx_state, + ctx->ctx_smpl_vaddr, + ctx->ctx_smpl_hdr, + ctx->ctx_msgq_head, + ctx->ctx_msgq_tail, + ctx->ctx_saved_psr_up); + } + local_irq_restore(flags); +} + +/* + * called from process.c:copy_thread(). task is new child. + */ +void +pfm_inherit(struct task_struct *task, struct pt_regs *regs) +{ + struct thread_struct *thread; + + DPRINT(("perfmon: pfm_inherit clearing state for [%d]\n", task->pid)); + + thread = &task->thread; + + /* + * cut links inherited from parent (current) + */ + thread->pfm_context = NULL; + + PFM_SET_WORK_PENDING(task, 0); + + /* + * the psr bits are already set properly in copy_threads() + */ +} +#else /* !CONFIG_PERFMON */ +asmlinkage long +sys_perfmonctl (int fd, int cmd, void *arg, int count) +{ + return -ENOSYS; +} +#endif /* CONFIG_PERFMON */ diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile b/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile new file mode 100644 index 0000000000..aad27a718e --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile @@ -0,0 +1,10 @@ +obj-$(CONFIG_OPROFILE) += oprofile.o + +DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ + oprof.o cpu_buffer.o buffer_sync.o \ + event_buffer.o oprofile_files.o \ + oprofilefs.o oprofile_stats.o \ + timer_int.o ) + +oprofile-y := $(DRIVER_OBJS) init.o backtrace.o +oprofile-$(CONFIG_PERFMON) += perfmon.o diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c b/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c new file mode 100644 index 0000000000..125a602a66 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c @@ -0,0 +1,38 @@ +/** + * @file init.c + * + * @remark Copyright 2002 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include + +extern int perfmon_init(struct oprofile_operations * ops); +extern void perfmon_exit(void); +extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth); + +int __init oprofile_arch_init(struct oprofile_operations * ops) +{ + int ret = -ENODEV; + +#ifdef CONFIG_PERFMON + /* perfmon_init() can fail, but we have no way to report it */ + ret = perfmon_init(ops); +#endif + ops->backtrace = ia64_backtrace; + + return ret; +} + + +void oprofile_arch_exit(void) +{ +#ifdef CONFIG_PERFMON + perfmon_exit(); +#endif +} diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c b/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c new file mode 100644 index 0000000000..b7975a469f --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c @@ -0,0 +1,100 @@ +/** + * @file perfmon.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include +#include + +static int allow_ints; + +static int +perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, + struct pt_regs *regs, unsigned long stamp) +{ + int event = arg->pmd_eventid; + + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; + + /* the owner of the oprofile event buffer may have exited + * without perfmon being shutdown (e.g. SIGSEGV) + */ + if (allow_ints) + oprofile_add_sample(regs, event); + return 0; +} + + +static int perfmon_start(void) +{ + allow_ints = 1; + return 0; +} + + +static void perfmon_stop(void) +{ + allow_ints = 0; +} + + +#define OPROFILE_FMT_UUID { \ + 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } + +static pfm_buffer_fmt_t oprofile_fmt = { + .fmt_name = "oprofile_format", + .fmt_uuid = OPROFILE_FMT_UUID, + .fmt_handler = perfmon_handler, +}; + + +static char * get_cpu_type(void) +{ + __u8 family = local_cpu_data->family; + + switch (family) { + case 0x07: + return "ia64/itanium"; + case 0x1f: + return "ia64/itanium2"; + default: + return "ia64/ia64"; + } +} + + +/* all the ops are handled via userspace for IA64 perfmon */ + +static int using_perfmon; + +int perfmon_init(struct oprofile_operations * ops) +{ + int ret = pfm_register_buffer_fmt(&oprofile_fmt); + if (ret) + return -ENODEV; + + ops->cpu_type = get_cpu_type(); + ops->start = perfmon_start; + ops->stop = perfmon_stop; + using_perfmon = 1; + printk(KERN_INFO "oprofile: using perfmon.\n"); + return 0; +} + + +void perfmon_exit(void) +{ + if (!using_perfmon) + return; + + pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); +} From 8508962bbe811d590d482df0e9537e41a7290e19 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 11:26:14 -0700 Subject: [PATCH 043/282] [IA64] import linux/arch/ia64/oprofile/perfmon.c To xen/arch/ia64/xen/oprofile/perfmon.c Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/oprofile/perfmon.c | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 xen/arch/ia64/xen/oprofile/perfmon.c diff --git a/xen/arch/ia64/xen/oprofile/perfmon.c b/xen/arch/ia64/xen/oprofile/perfmon.c new file mode 100644 index 0000000000..b7975a469f --- /dev/null +++ b/xen/arch/ia64/xen/oprofile/perfmon.c @@ -0,0 +1,100 @@ +/** + * @file perfmon.c + * + * @remark Copyright 2003 OProfile authors + * @remark Read the file COPYING + * + * @author John Levon + */ + +#include +#include +#include +#include +#include +#include +#include + +static int allow_ints; + +static int +perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, + struct pt_regs *regs, unsigned long stamp) +{ + int event = arg->pmd_eventid; + + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; + + /* the owner of the oprofile event buffer may have exited + * without perfmon being shutdown (e.g. SIGSEGV) + */ + if (allow_ints) + oprofile_add_sample(regs, event); + return 0; +} + + +static int perfmon_start(void) +{ + allow_ints = 1; + return 0; +} + + +static void perfmon_stop(void) +{ + allow_ints = 0; +} + + +#define OPROFILE_FMT_UUID { \ + 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } + +static pfm_buffer_fmt_t oprofile_fmt = { + .fmt_name = "oprofile_format", + .fmt_uuid = OPROFILE_FMT_UUID, + .fmt_handler = perfmon_handler, +}; + + +static char * get_cpu_type(void) +{ + __u8 family = local_cpu_data->family; + + switch (family) { + case 0x07: + return "ia64/itanium"; + case 0x1f: + return "ia64/itanium2"; + default: + return "ia64/ia64"; + } +} + + +/* all the ops are handled via userspace for IA64 perfmon */ + +static int using_perfmon; + +int perfmon_init(struct oprofile_operations * ops) +{ + int ret = pfm_register_buffer_fmt(&oprofile_fmt); + if (ret) + return -ENODEV; + + ops->cpu_type = get_cpu_type(); + ops->start = perfmon_start; + ops->stop = perfmon_stop; + using_perfmon = 1; + printk(KERN_INFO "oprofile: using perfmon.\n"); + return 0; +} + + +void perfmon_exit(void) +{ + if (!using_perfmon) + return; + + pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); +} From e75f92933e2ce4438bc15c98f75ee8b50e5ad682 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 11:31:45 -0700 Subject: [PATCH 044/282] [IA64] increase xen side pmu constatns for motecito. Signed-off-by: Isaku Yamahata --- xen/include/asm-ia64/linux-xen/asm/processor.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/xen/include/asm-ia64/linux-xen/asm/processor.h b/xen/include/asm-ia64/linux-xen/asm/processor.h index 976c0960d6..fb753e0d16 100644 --- a/xen/include/asm-ia64/linux-xen/asm/processor.h +++ b/xen/include/asm-ia64/linux-xen/asm/processor.h @@ -28,8 +28,18 @@ * Limits for PMC and PMD are set to less than maximum architected values * but should be sufficient for a while */ +#ifdef XEN +/* + * These are increased in linux-2.6.16. Montecito requires 35PMDs. + * This ifdef will become unnecessary when this header file is + * upgraded to 2.6.16 or newer. + */ +#define IA64_NUM_PMC_REGS 64 +#define IA64_NUM_PMD_REGS 64 +#else #define IA64_NUM_PMC_REGS 32 #define IA64_NUM_PMD_REGS 32 +#endif #define DEFAULT_MAP_BASE __IA64_UL_CONST(0x2000000000000000) #define DEFAULT_TASK_SIZE __IA64_UL_CONST(0xa000000000000000) From e5b50237ff66cba6c3b3c94b420d6fe40fd3f8d4 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 11:34:03 -0700 Subject: [PATCH 045/282] [IA64] add dummy empty header files necessary for xenoprof/ia64 Signed-off-by: Isaku Yamahata --- xen/include/asm-ia64/linux-null/asm/signal.h | 1 + xen/include/asm-ia64/linux-null/linux/capability.h | 1 + xen/include/asm-ia64/linux-null/linux/completion.h | 1 + xen/include/asm-ia64/linux-null/linux/mount.h | 1 + xen/include/asm-ia64/linux-null/linux/pagemap.h | 1 + xen/include/asm-ia64/linux-null/linux/poll.h | 1 + xen/include/asm-ia64/linux-null/linux/rcupdate.h | 1 + xen/include/asm-ia64/linux-null/linux/sysctl.h | 1 + xen/include/asm-ia64/linux-null/linux/vfs.h | 1 + xen/include/asm-ia64/linux-null/linux/vmalloc.h | 1 + 10 files changed, 10 insertions(+) create mode 100644 xen/include/asm-ia64/linux-null/asm/signal.h create mode 100644 xen/include/asm-ia64/linux-null/linux/capability.h create mode 100644 xen/include/asm-ia64/linux-null/linux/completion.h create mode 100644 xen/include/asm-ia64/linux-null/linux/mount.h create mode 100644 xen/include/asm-ia64/linux-null/linux/pagemap.h create mode 100644 xen/include/asm-ia64/linux-null/linux/poll.h create mode 100644 xen/include/asm-ia64/linux-null/linux/rcupdate.h create mode 100644 xen/include/asm-ia64/linux-null/linux/sysctl.h create mode 100644 xen/include/asm-ia64/linux-null/linux/vfs.h create mode 100644 xen/include/asm-ia64/linux-null/linux/vmalloc.h diff --git a/xen/include/asm-ia64/linux-null/asm/signal.h b/xen/include/asm-ia64/linux-null/asm/signal.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/asm/signal.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/capability.h b/xen/include/asm-ia64/linux-null/linux/capability.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/capability.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/completion.h b/xen/include/asm-ia64/linux-null/linux/completion.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/completion.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/mount.h b/xen/include/asm-ia64/linux-null/linux/mount.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/mount.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/pagemap.h b/xen/include/asm-ia64/linux-null/linux/pagemap.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/pagemap.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/poll.h b/xen/include/asm-ia64/linux-null/linux/poll.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/poll.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/rcupdate.h b/xen/include/asm-ia64/linux-null/linux/rcupdate.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/rcupdate.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/sysctl.h b/xen/include/asm-ia64/linux-null/linux/sysctl.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/sysctl.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/vfs.h b/xen/include/asm-ia64/linux-null/linux/vfs.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/vfs.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ diff --git a/xen/include/asm-ia64/linux-null/linux/vmalloc.h b/xen/include/asm-ia64/linux-null/linux/vmalloc.h new file mode 100644 index 0000000000..29f4f4cd69 --- /dev/null +++ b/xen/include/asm-ia64/linux-null/linux/vmalloc.h @@ -0,0 +1 @@ +/* This file is intentionally left empty. */ From b496644a2b007274b9aeb060a556b9993ab529d2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 28 Nov 2006 18:41:42 +0000 Subject: [PATCH 046/282] A trivial fix. login_unconditionally needs to be called with self.login_unconditionally to avoid "global name 'login_unconditionally' is not defined" Signed-off-by: Stefan Berger --- tools/python/xen/xend/XendAuthSessions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendAuthSessions.py b/tools/python/xen/xend/XendAuthSessions.py index 616724b96b..4081177597 100644 --- a/tools/python/xen/xend/XendAuthSessions.py +++ b/tools/python/xen/xend/XendAuthSessions.py @@ -55,7 +55,7 @@ class XendAuthSessions: @return: Session UUID """ if self.is_authorized(username, password): - return login_unconditionally(username) + return self.login_unconditionally(username) raise XendError("Login failed") From 2a615d53c7bb8fd4652000daa6149f9ecbb6af3b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 21:35:13 -0700 Subject: [PATCH 047/282] [IA64] xenoprof ia64 xen side Signed-off-by: Isaku Yamahata Signed-off-by: Alex Williamson --- xen/arch/ia64/Rules.mk | 1 + xen/arch/ia64/linux-xen/Makefile | 2 + xen/arch/ia64/linux-xen/perfmon.c | 948 +++++++++++++++++- .../ia64/linux-xen/perfmon_default_smpl.c | 14 + xen/arch/ia64/linux/Makefile | 1 + xen/arch/ia64/xen/Makefile | 2 + xen/arch/ia64/xen/dom0_ops.c | 6 + xen/arch/ia64/xen/domain.c | 32 +- xen/arch/ia64/xen/hypercall.c | 2 +- xen/arch/ia64/xen/oprofile/Makefile | 1 + xen/arch/ia64/xen/oprofile/perfmon.c | 230 +++-- xen/arch/ia64/xen/oprofile/xenoprof.c | 56 ++ xen/include/asm-ia64/config.h | 3 + xen/include/asm-ia64/domain.h | 4 + xen/include/asm-ia64/linux-xen/asm/perfmon.h | 8 + xen/include/asm-ia64/xenoprof.h | 64 ++ xen/include/public/arch-ia64.h | 22 + 17 files changed, 1327 insertions(+), 69 deletions(-) create mode 100644 xen/arch/ia64/xen/oprofile/Makefile create mode 100644 xen/arch/ia64/xen/oprofile/xenoprof.c create mode 100644 xen/include/asm-ia64/xenoprof.h diff --git a/xen/arch/ia64/Rules.mk b/xen/arch/ia64/Rules.mk index 8f69704d7d..82f5953aaf 100644 --- a/xen/arch/ia64/Rules.mk +++ b/xen/arch/ia64/Rules.mk @@ -3,6 +3,7 @@ HAS_ACPI := y HAS_VGA := y +xenoprof := y VALIDATE_VT ?= n no_warns ?= n xen_ia64_expose_p2m ?= y diff --git a/xen/arch/ia64/linux-xen/Makefile b/xen/arch/ia64/linux-xen/Makefile index b7f8257579..980ea8e746 100644 --- a/xen/arch/ia64/linux-xen/Makefile +++ b/xen/arch/ia64/linux-xen/Makefile @@ -18,3 +18,5 @@ obj-y += unwind.o obj-y += iosapic.o obj-y += numa.o obj-y += mm_numa.o +obj-y += perfmon.o +obj-y += perfmon_default_smpl.o diff --git a/xen/arch/ia64/linux-xen/perfmon.c b/xen/arch/ia64/linux-xen/perfmon.c index 9b42b02b85..cc776c631a 100644 --- a/xen/arch/ia64/linux-xen/perfmon.c +++ b/xen/arch/ia64/linux-xen/perfmon.c @@ -17,6 +17,12 @@ * * More information about perfmon available at: * http://www.hpl.hp.com/research/linux/perfmon + * + * + * For Xen/IA64 xenoprof + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * */ #include @@ -42,7 +48,11 @@ #include #include +#ifndef XEN #include +#else +#include +#endif #include #include #include @@ -52,6 +62,15 @@ #include #include +#ifdef XEN +#include +#include +#define CONFIG_PERFMON +#define pid vcpu_id +#define thread arch._thread +#define task_pt_regs vcpu_regs +#endif + #ifdef CONFIG_PERFMON /* * perfmon context state @@ -287,7 +306,9 @@ typedef struct pfm_context { unsigned long ctx_ovfl_regs[4]; /* which registers overflowed (notification) */ +#ifndef XEN struct completion ctx_restart_done; /* use for blocking notification mode */ +#endif unsigned long ctx_used_pmds[4]; /* bitmask of PMD used */ unsigned long ctx_all_pmds[4]; /* bitmask of all accessible PMDs */ @@ -320,6 +341,7 @@ typedef struct pfm_context { unsigned long ctx_smpl_size; /* size of sampling buffer */ void *ctx_smpl_vaddr; /* user level virtual address of smpl buffer */ +#ifndef XEN wait_queue_head_t ctx_msgq_wait; pfm_msg_t ctx_msgq[PFM_MAX_MSGS]; int ctx_msgq_head; @@ -327,6 +349,7 @@ typedef struct pfm_context { struct fasync_struct *ctx_async_queue; wait_queue_head_t ctx_zombieq; /* termination cleanup wait queue */ +#endif } pfm_context_t; /* @@ -371,6 +394,9 @@ typedef struct { unsigned int pfs_sys_use_dbregs; /* incremented when a system wide session uses debug regs */ unsigned int pfs_ptrace_use_dbregs; /* incremented when a process uses debug regs */ struct task_struct *pfs_sys_session[NR_CPUS]; /* point to task owning a system-wide session */ +#ifdef XEN +#define XENOPROF_TASK ((struct task_struct*)1) +#endif } pfm_session_t; /* @@ -499,10 +525,14 @@ typedef struct { static pfm_stats_t pfm_stats[NR_CPUS]; static pfm_session_t pfm_sessions; /* global sessions information */ +#ifndef XEN static DEFINE_SPINLOCK(pfm_alt_install_check); +#endif static pfm_intr_handler_desc_t *pfm_alt_intr_handler; +#ifndef XEN static struct proc_dir_entry *perfmon_dir; +#endif static pfm_uuid_t pfm_null_uuid = {0,}; static spinlock_t pfm_buffer_fmt_lock; @@ -514,6 +544,7 @@ static pmu_config_t *pmu_conf; pfm_sysctl_t pfm_sysctl; EXPORT_SYMBOL(pfm_sysctl); +#ifndef XEN static ctl_table pfm_ctl_table[]={ {1, "debug", &pfm_sysctl.debug, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, {2, "debug_ovfl", &pfm_sysctl.debug_ovfl, sizeof(int), 0666, NULL, &proc_dointvec, NULL,}, @@ -533,10 +564,12 @@ static struct ctl_table_header *pfm_sysctl_header; static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs); static int pfm_flush(struct file *filp); +#endif #define pfm_get_cpu_var(v) __ia64_per_cpu_var(v) #define pfm_get_cpu_data(a,b) per_cpu(a, b) +#ifndef XEN static inline void pfm_put_task(struct task_struct *task) { @@ -568,6 +601,7 @@ pfm_unreserve_page(unsigned long a) { ClearPageReserved(vmalloc_to_page((void*)a)); } +#endif static inline unsigned long pfm_protect_ctx_ctxsw(pfm_context_t *x) @@ -582,6 +616,7 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) spin_unlock(&(x)->ctx_lock); } +#ifndef XEN static inline unsigned int pfm_do_munmap(struct mm_struct *mm, unsigned long addr, size_t len, int acct) { @@ -606,16 +641,19 @@ static struct file_system_type pfm_fs_type = { .get_sb = pfmfs_get_sb, .kill_sb = kill_anon_super, }; +#endif DEFINE_PER_CPU(unsigned long, pfm_syst_info); DEFINE_PER_CPU(struct task_struct *, pmu_owner); DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); DEFINE_PER_CPU(unsigned long, pmu_activation_number); +#ifndef XEN EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info); /* forward declaration */ static struct file_operations pfm_file_ops; +#endif /* * forward declarations @@ -641,7 +679,9 @@ static pmu_config_t *pmu_confs[]={ }; +#ifndef XEN static int pfm_end_notify_user(pfm_context_t *ctx); +#endif static inline void pfm_clear_psr_pp(void) @@ -750,6 +790,7 @@ pfm_write_soft_counter(pfm_context_t *ctx, int i, unsigned long val) ia64_set_pmd(i, val & ovfl_val); } +#ifndef XEN static pfm_msg_t * pfm_get_new_msg(pfm_context_t *ctx) { @@ -837,6 +878,7 @@ pfm_rvfree(void *mem, unsigned long size) } return; } +#endif static pfm_context_t * pfm_context_alloc(void) @@ -864,6 +906,7 @@ pfm_context_free(pfm_context_t *ctx) } } +#ifndef XEN static void pfm_mask_monitoring(struct task_struct *task) { @@ -1034,6 +1077,7 @@ pfm_restore_monitoring(struct task_struct *task) } pfm_set_psr_l(psr); } +#endif static inline void pfm_save_pmds(unsigned long *pmds, unsigned long mask) @@ -1047,6 +1091,7 @@ pfm_save_pmds(unsigned long *pmds, unsigned long mask) } } +#ifndef XEN /* * reload from thread state (used for ctxw only) */ @@ -1100,7 +1145,37 @@ pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx) ctx->ctx_pmds[i].val)); } } +#else +static inline void +xenpfm_restore_pmds(pfm_context_t* ctx) +{ + int i; + unsigned long ovfl_val = pmu_conf->ovfl_val; + unsigned long mask = ctx->ctx_all_pmds[0]; + unsigned long val; + for (i = 0; mask; i++, mask >>= 1) { + if ((mask & 0x1) == 0) + continue; + + val = ctx->ctx_pmds[i].val; + /* + * We break up the 64 bit value into 2 pieces + * the lower bits go to the machine state in the + * thread (will be reloaded on ctxsw in). + * The upper part stays in the soft-counter. + */ + if (PMD_IS_COUNTING(i)) { + ctx->ctx_pmds[i].val = val & ~ovfl_val; + val &= ovfl_val; + } + ia64_set_pmd(i, val); + } + ia64_srlz_d(); +} +#endif + +#ifndef XEN /* * propagate PMC from context to thread-state */ @@ -1133,6 +1208,23 @@ pfm_restore_pmcs(unsigned long *pmcs, unsigned long mask) } ia64_srlz_d(); } +#else +static inline void +xenpfm_restore_pmcs(pfm_context_t* ctx) +{ + int i; + unsigned long mask = ctx->ctx_all_pmcs[0]; + + for (i = 0; mask; i++, mask >>= 1) { + if ((mask & 0x1) == 0) + continue; + ia64_set_pmc(i, ctx->ctx_pmcs[i]); + DPRINT(("pmc[%d]=0x%lx\n", i, ctx->ctx_pmcs[i])); + } + ia64_srlz_d(); + +} +#endif static inline int pfm_uuid_cmp(pfm_uuid_t a, pfm_uuid_t b) @@ -1305,7 +1397,11 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) DPRINT(("reserving system wide session on CPU%u currently on CPU%u\n", cpu, smp_processor_id())); +#ifndef XEN pfm_sessions.pfs_sys_session[cpu] = task; +#else + pfm_sessions.pfs_sys_session[cpu] = XENOPROF_TASK; +#endif pfm_sessions.pfs_sys_sessions++ ; @@ -1332,7 +1428,11 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) error_conflict: DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", +#ifndef XEN pfm_sessions.pfs_sys_session[cpu]->pid, +#else + -1, +#endif cpu)); abort: UNLOCK_PFS(flags); @@ -1392,6 +1492,7 @@ pfm_unreserve_session(pfm_context_t *ctx, int is_syswide, unsigned int cpu) return 0; } +#ifndef XEN /* * removes virtual mapping of the sampling buffer. * IMPORTANT: cannot be called with interrupts disable, e.g. inside @@ -1428,6 +1529,7 @@ pfm_remove_smpl_mapping(struct task_struct *task, void *vaddr, unsigned long siz return 0; } +#endif /* * free actual physical storage used by sampling buffer @@ -1477,6 +1579,7 @@ pfm_exit_smpl_buffer(pfm_buffer_fmt_t *fmt) } +#ifndef XEN /* * pfmfs should _never_ be mounted by userland - too much of security hassle, * no real gain from having the whole whorehouse mounted. So we don't need @@ -1901,6 +2004,7 @@ pfm_flush(struct file *filp) return 0; } +#endif /* * called either on explicit close() or from exit_files(). * Only the LAST user of the file gets to this point, i.e., it is @@ -1916,19 +2020,27 @@ pfm_flush(struct file *filp) * When called from exit_files(), the current task is not yet ZOMBIE but we * flush the PMU state to the context. */ +#ifndef XEN static int pfm_close(struct inode *inode, struct file *filp) +#else +static int +pfm_close(pfm_context_t *ctx) +#endif { +#ifndef XEN pfm_context_t *ctx; struct task_struct *task; struct pt_regs *regs; DECLARE_WAITQUEUE(wait, current); unsigned long flags; +#endif unsigned long smpl_buf_size = 0UL; void *smpl_buf_addr = NULL; int free_possible = 1; int state, is_system; +#ifndef XEN DPRINT(("pfm_close called private=%p\n", filp->private_data)); if (PFM_IS_FILE(filp) == 0) { @@ -1943,10 +2055,14 @@ pfm_close(struct inode *inode, struct file *filp) } PROTECT_CTX(ctx, flags); +#else + BUG_ON(!spin_is_locked(&ctx->ctx_lock)); +#endif state = ctx->ctx_state; is_system = ctx->ctx_fl_system; +#ifndef XEN task = PFM_CTX_TASK(ctx); regs = task_pt_regs(task); @@ -2045,8 +2161,15 @@ pfm_close(struct inode *inode, struct file *filp) pfm_context_unload(ctx, NULL, 0, regs); #endif } +#else + /* XXX XEN */ + /* unload context */ + BUG_ON(state != PFM_CTX_UNLOADED); +#endif +#ifndef XEN doit: +#endif /* reload state, may have changed during opening of critical section */ state = ctx->ctx_state; @@ -2087,6 +2210,7 @@ doit: pfm_unreserve_session(ctx, ctx->ctx_fl_system , ctx->ctx_cpu); } +#ifndef XEN /* * disconnect file descriptor from context must be done * before we unlock. @@ -2107,6 +2231,9 @@ doit: * MUST be done with interrupts ENABLED. */ if (smpl_buf_addr) pfm_rvfree(smpl_buf_addr, smpl_buf_size); +#else + UNPROTECT_CTX_NOIRQ(ctx); +#endif /* * return the memory used by the context @@ -2116,6 +2243,7 @@ doit: return 0; } +#ifndef XEN static int pfm_no_open(struct inode *irrelevant, struct file *dontcare) { @@ -2255,6 +2383,7 @@ pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long ad } return 0; } +#endif /* * allocate a sampling buffer and remaps it into the user address space of the task @@ -2262,6 +2391,7 @@ pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long ad static int pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned long rsize, void **user_vaddr) { +#ifndef XEN struct mm_struct *mm = task->mm; struct vm_area_struct *vma = NULL; unsigned long size; @@ -2374,8 +2504,13 @@ error_kmem: pfm_rvfree(smpl_buf, size); return -ENOMEM; +#else + /* XXX */ + return 0; +#endif } +#ifndef XEN /* * XXX: do something better here */ @@ -2399,6 +2534,7 @@ pfm_bad_permissions(struct task_struct *task) || (current->gid != task->sgid) || (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE); } +#endif static int pfarg_is_sane(struct task_struct *task, pfarg_context_t *pfx) @@ -2535,6 +2671,7 @@ pfm_reset_pmu_state(pfm_context_t *ctx) ctx->ctx_used_dbrs[0] = 0UL; } +#ifndef XEN static int pfm_ctx_getsize(void *arg, size_t *sz) { @@ -2642,20 +2779,31 @@ pfm_get_task(pfm_context_t *ctx, pid_t pid, struct task_struct **task) } return ret; } +#endif - +#ifndef XEN static int pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) +#else +static pfm_context_t* +pfm_context_create(pfarg_context_t* req) +#endif { +#ifndef XEN pfarg_context_t *req = (pfarg_context_t *)arg; struct file *filp; +#else + pfm_context_t *ctx; +#endif int ctx_flags; int ret; +#ifndef XEN /* let's check the arguments first */ ret = pfarg_is_sane(current, req); if (ret < 0) return ret; +#endif ctx_flags = req->ctx_flags; @@ -2664,6 +2812,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg ctx = pfm_context_alloc(); if (!ctx) goto error; +#ifndef XEN ret = pfm_alloc_fd(&filp); if (ret < 0) goto error_file; @@ -2673,6 +2822,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg * attach context to file */ filp->private_data = ctx; +#endif /* * does the user want to sample? @@ -2704,10 +2854,12 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0; */ +#ifndef XEN /* * init restart semaphore to locked */ init_completion(&ctx->ctx_restart_done); +#endif /* * activation is used in SMP only @@ -2715,12 +2867,14 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg ctx->ctx_last_activation = PFM_INVALID_ACTIVATION; SET_LAST_CPU(ctx, -1); +#ifndef XEN /* * initialize notification message queue */ ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0; init_waitqueue_head(&ctx->ctx_msgq_wait); init_waitqueue_head(&ctx->ctx_zombieq); +#endif DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n", ctx, @@ -2736,19 +2890,35 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg */ pfm_reset_pmu_state(ctx); +#ifndef XEN return 0; +#else + return ctx; +#endif buffer_error: +#ifndef XEN pfm_free_fd(ctx->ctx_fd, filp); +#endif if (ctx->ctx_buf_fmt) { +#ifndef XEN pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs); +#else + pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, NULL); +#endif } +#ifndef XEN error_file: +#endif pfm_context_free(ctx); error: +#ifndef XEN return ret; +#else + return NULL; +#endif } static inline unsigned long @@ -2860,7 +3030,9 @@ pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset) static int pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { +#ifndef XEN struct thread_struct *thread = NULL; +#endif struct task_struct *task; pfarg_reg_t *req = (pfarg_reg_t *)arg; unsigned long value, pmc_pm; @@ -2877,9 +3049,14 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) is_system = ctx->ctx_fl_system; task = ctx->ctx_task; impl_pmds = pmu_conf->impl_pmds[0]; +#ifdef XEN + task = NULL; + BUG_ON(regs != NULL); +#endif if (state == PFM_CTX_ZOMBIE) return -EINVAL; +#ifndef XEN if (is_loaded) { thread = &task->thread; /* @@ -2893,6 +3070,13 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) } can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; } +#else + /* XXX FIXME */ + if (state != PFM_CTX_UNLOADED) { + return -EBUSY; + } +#endif + expert_mode = pfm_sysctl.expert_mode; for (i = 0; i < count; i++, req++) { @@ -3046,6 +3230,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) */ ctx->ctx_pmcs[cnum] = value; +#ifndef XEN if (is_loaded) { /* * write thread state @@ -3071,6 +3256,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) } #endif } +#endif DPRINT(("pmc[%u]=0x%lx ld=%d apmu=%d flags=0x%x all_pmcs=0x%lx used_pmds=0x%lx eventid=%ld smpl_pmds=0x%lx reset_pmds=0x%lx reloads_pmcs=0x%lx used_monitors=0x%lx ovfl_regs=0x%lx\n", cnum, @@ -3102,7 +3288,9 @@ error: static int pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { +#ifndef XEN struct thread_struct *thread = NULL; +#endif struct task_struct *task; pfarg_reg_t *req = (pfarg_reg_t *)arg; unsigned long value, hw_value, ovfl_mask; @@ -3118,9 +3306,14 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) is_system = ctx->ctx_fl_system; ovfl_mask = pmu_conf->ovfl_val; task = ctx->ctx_task; +#ifdef XEN + task = NULL; + BUG_ON(regs != NULL); +#endif if (unlikely(state == PFM_CTX_ZOMBIE)) return -EINVAL; +#ifndef XEN /* * on both UP and SMP, we can only write to the PMC when the task is * the owner of the local PMU. @@ -3138,6 +3331,12 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) } can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; } +#else + /* XXX FIXME */ + if (state != PFM_CTX_UNLOADED) { + return -EBUSY; + } +#endif expert_mode = pfm_sysctl.expert_mode; for (i = 0; i < count; i++, req++) { @@ -3230,6 +3429,8 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; } + /* XXX FIXME */ +#ifndef XEN if (is_loaded) { /* * write thread state @@ -3252,6 +3453,7 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) #endif } } +#endif DPRINT(("pmd[%u]=0x%lx ld=%d apmu=%d, hw_value=0x%lx ctx_pmd=0x%lx short_reset=0x%lx " "long_reset=0x%lx notify=%c seed=0x%lx mask=0x%lx used_pmds=0x%lx reset_pmds=0x%lx reload_pmds=0x%lx all_pmds=0x%lx ovfl_regs=0x%lx\n", @@ -3288,6 +3490,7 @@ abort_mission: return ret; } +#ifndef XEN /* * By the way of PROTECT_CONTEXT(), interrupts are masked while we are in this function. * Therefore we know, we do not have to worry about the PMU overflow interrupt. If an @@ -3471,6 +3674,7 @@ pfm_mod_read_pmds(struct task_struct *task, void *req, unsigned int nreq, struct return pfm_read_pmds(ctx, req, nreq, regs); } EXPORT_SYMBOL(pfm_mod_read_pmds); +#endif /* * Only call this function when a process it trying to @@ -3552,6 +3756,7 @@ pfm_release_debug_registers(struct task_struct *task) return ret; } +#ifndef XEN static int pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { @@ -3720,6 +3925,7 @@ pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) } return 0; } +#endif /* * arg can be NULL and count can be zero for this function @@ -3727,7 +3933,9 @@ pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { +#ifndef XEN struct thread_struct *thread = NULL; +#endif struct task_struct *task; pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg; unsigned long flags; @@ -3744,6 +3952,12 @@ pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_ is_loaded = state == PFM_CTX_LOADED ? 1 : 0; is_system = ctx->ctx_fl_system; task = ctx->ctx_task; +#ifdef XEN + task = NULL; + BUG_ON(regs != NULL); + /* currently dbrs, ibrs aren't supported */ + BUG(); +#endif if (state == PFM_CTX_ZOMBIE) return -EINVAL; @@ -3752,6 +3966,10 @@ pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_ * the owner of the local PMU. */ if (is_loaded) { +#ifdef XEN + /* XXX */ + return -EBUSY; +#else thread = &task->thread; /* * In system wide and when the context is loaded, access can only happen @@ -3763,6 +3981,7 @@ pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_ return -EBUSY; } can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; +#endif } /* @@ -3777,10 +3996,14 @@ pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_ /* * don't bother if we are loaded and task is being debugged */ +#ifndef XEN if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) { DPRINT(("debug registers already in use for [%d]\n", task->pid)); return -EBUSY; } +#else + /* Currently no support for is_loaded, see -EBUSY above */ +#endif /* * check for debug registers in system wide mode @@ -3819,7 +4042,9 @@ pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count, struct pt_ * is shared by all processes running on it */ if (first_time && can_access_pmu) { +#ifndef XEN DPRINT(("[%d] clearing ibrs, dbrs\n", task->pid)); +#endif for (i=0; i < pmu_conf->num_ibrs; i++) { ia64_set_ibr(i, 0UL); ia64_dv_serialize_instruction(); @@ -3983,6 +4208,7 @@ pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) return 0; } +#ifndef XEN static int pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { @@ -4201,12 +4427,15 @@ pfm_check_task_exist(pfm_context_t *ctx) return ret; } +#endif static int pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { struct task_struct *task; +#ifndef XEN struct thread_struct *thread; +#endif struct pfm_context_t *old; unsigned long flags; #ifndef CONFIG_SMP @@ -4220,6 +4449,17 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) state = ctx->ctx_state; is_system = ctx->ctx_fl_system; +#ifdef XEN + task = NULL; + old = NULL; + pmcs_source = pmds_source = NULL; +#ifndef CONFIG_SMP + owner_task = NULL; +#endif + flags = 0; + BUG_ON(count != 0); + BUG_ON(regs != NULL); +#endif /* * can only load from unloaded or terminated state */ @@ -4230,6 +4470,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) return -EBUSY; } +#ifndef XEN DPRINT(("load_pid [%d] using_dbreg=%d\n", req->load_pid, ctx->ctx_fl_using_dbreg)); if (CTX_OVFL_NOBLOCK(ctx) == 0 && req->load_pid == current->pid) { @@ -4255,8 +4496,16 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) } thread = &task->thread; +#else + BUG_ON(!spin_is_locked(&ctx->ctx_lock)); + if (!is_system) { + ret = -EINVAL; + goto error; + } +#endif ret = 0; +#ifndef XEN /* * cannot load a context which is using range restrictions, * into a task that is being debugged. @@ -4284,6 +4533,9 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) if (ret) goto error; } +#else + BUG_ON(ctx->ctx_fl_using_dbreg); +#endif /* * SMP system-wide monitoring implies self-monitoring. @@ -4318,6 +4570,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) * * XXX: needs to be atomic */ +#ifndef XEN DPRINT(("before cmpxchg() old_ctx=%p new_ctx=%p\n", thread->pfm_context, ctx)); @@ -4329,6 +4582,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) } pfm_reset_msgq(ctx); +#endif ctx->ctx_state = PFM_CTX_LOADED; @@ -4346,9 +4600,14 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) if (ctx->ctx_fl_excl_idle) PFM_CPUINFO_SET(PFM_CPUINFO_EXCL_IDLE); } else { +#ifndef XEN thread->flags |= IA64_THREAD_PM_VALID; +#else + BUG(); +#endif } +#ifndef XEN /* * propagate into thread-state */ @@ -4417,12 +4676,29 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) ctx->ctx_saved_psr_up = 0UL; ia64_psr(regs)->up = ia64_psr(regs)->pp = 0; } +#else + BUG_ON(!is_system); + + /* load pmds, pmcs */ + xenpfm_restore_pmds(ctx); + xenpfm_restore_pmcs(ctx); + + ctx->ctx_reload_pmcs[0] = 0UL; + ctx->ctx_reload_pmds[0] = 0UL; + + BUG_ON(ctx->ctx_fl_using_dbreg); + + SET_PMU_OWNER(NULL, ctx); +#endif ret = 0; +#ifndef XEN error_unres: if (ret) pfm_unreserve_session(ctx, ctx->ctx_fl_system, the_cpu); +#endif error: +#ifndef XEN /* * we must undo the dbregs setting (for system-wide) */ @@ -4445,6 +4721,9 @@ error: } } } +#else + BUG_ON(set_dbregs); +#endif return ret; } @@ -4466,7 +4745,15 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg int prev_state, is_system; int ret; +#ifndef XEN DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); +#else + task = NULL; + tregs = NULL; + BUG_ON(arg != NULL); + BUG_ON(count != 0); + BUG_ON(regs != NULL); +#endif prev_state = ctx->ctx_state; is_system = ctx->ctx_fl_system; @@ -4482,8 +4769,13 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg /* * clear psr and dcr bits */ +#ifndef XEN ret = pfm_stop(ctx, NULL, 0, regs); if (ret) return ret; +#else + /* caller does it by hand */ + ret = 0; +#endif ctx->ctx_state = PFM_CTX_UNLOADED; @@ -4515,10 +4807,12 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg if (prev_state != PFM_CTX_ZOMBIE) pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); +#ifndef XEN /* * disconnect context from task */ task->thread.pfm_context = NULL; +#endif /* * disconnect task from context */ @@ -4530,6 +4824,7 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg return 0; } +#ifndef XEN /* * per-task mode */ @@ -4584,9 +4879,14 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg DPRINT(("disconnected [%d] from context\n", task->pid)); return 0; +#else + BUG(); + return -EINVAL; +#endif } +#ifndef XEN /* * called only from exit_thread(): task == current * we come here only if current has a context attached (loaded or masked) @@ -5210,6 +5510,9 @@ pfm_end_notify_user(pfm_context_t *ctx) return pfm_notify_user(ctx, msg); } +#else +#define pfm_ovfl_notify_user(ctx, ovfl_pmds) do {} while(0) +#endif /* * main overflow processing routine. @@ -5226,6 +5529,9 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str pfm_ovfl_ctrl_t ovfl_ctrl; unsigned int i, has_smpl; int must_notify = 0; +#ifdef XEN + BUG_ON(task != NULL); +#endif if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) goto stop_monitoring; @@ -5400,6 +5706,7 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str } if (ovfl_notify && ovfl_ctrl.bits.notify_user) { +#ifndef XEN /* * keep track of what to reset when unblocking */ @@ -5428,11 +5735,18 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str * anyway, so the signal receiver would come spin for nothing. */ must_notify = 1; +#else + gdprintk(XENLOG_INFO, "%s check!\n", __func__); +#endif } DPRINT_ovfl(("owner [%d] pending=%ld reason=%u ovfl_pmds=0x%lx ovfl_notify=0x%lx masked=%d\n", +#ifndef XEN GET_PMU_OWNER() ? GET_PMU_OWNER()->pid : -1, PFM_GET_WORK_PENDING(task), +#else + -1, 0UL, +#endif ctx->ctx_fl_trap_reason, ovfl_pmds, ovfl_notify, @@ -5441,9 +5755,13 @@ pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, str * in case monitoring must be stopped, we toggle the psr bits */ if (ovfl_ctrl.bits.mask_monitoring) { +#ifndef XEN pfm_mask_monitoring(task); ctx->ctx_state = PFM_CTX_MASKED; ctx->ctx_fl_can_restart = 1; +#else + gdprintk(XENLOG_INFO, "%s check!\n", __func__); +#endif } /* @@ -5513,14 +5831,22 @@ pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) */ pmc0 = ia64_get_pmc(0); +#ifndef XEN task = GET_PMU_OWNER(); +#else + task = NULL; +#endif ctx = GET_PMU_CTX(); /* * if we have some pending bits set * assumes : if any PMC0.bit[63-1] is set, then PMC0.fr = 1 */ +#ifndef XEN if (PMC0_HAS_OVFL(pmc0) && task) { +#else + if (PMC0_HAS_OVFL(pmc0)) { +#endif /* * we assume that pmc0.fr is always set here */ @@ -5528,8 +5854,10 @@ pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) /* sanity check */ if (!ctx) goto report_spurious1; +#ifndef XEN if (ctx->ctx_fl_system == 0 && (task->thread.flags & IA64_THREAD_PM_VALID) == 0) goto report_spurious2; +#endif PROTECT_CTX_NOPRINT(ctx, flags); @@ -5549,16 +5877,20 @@ pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) return retval; report_spurious1: +#ifndef XEN printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d has no PFM context\n", this_cpu, task->pid); +#endif pfm_unfreeze_pmu(); return -1; +#ifndef XEN /* XEN path doesn't take this goto */ report_spurious2: printk(KERN_INFO "perfmon: spurious overflow interrupt on CPU%d: process %d, invalid flag\n", this_cpu, task->pid); pfm_unfreeze_pmu(); return -1; +#endif } static irqreturn_t @@ -5600,6 +5932,7 @@ pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) return IRQ_HANDLED; } +#ifndef XEN /* * /proc/perfmon interface, for debug only */ @@ -5777,6 +6110,7 @@ pfm_proc_open(struct inode *inode, struct file *file) { return seq_open(file, &pfm_seq_ops); } +#endif /* @@ -5831,6 +6165,7 @@ pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_c } } +#ifndef XEN #ifdef CONFIG_SMP static void @@ -6326,6 +6661,7 @@ pfm_load_regs (struct task_struct *task) if (likely(psr_up)) pfm_set_psr_up(); } #endif /* CONFIG_SMP */ +#endif /* XEN */ /* * this function assumes monitoring is stopped @@ -6333,6 +6669,7 @@ pfm_load_regs (struct task_struct *task) static void pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) { +#ifndef XEN u64 pmc0; unsigned long mask2, val, pmd_val, ovfl_val; int i, can_access_pmu = 0; @@ -6438,14 +6775,20 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) ctx->ctx_pmds[i].val = val; } +#else + /* XXX */ +#endif } static struct irqaction perfmon_irqaction = { .handler = pfm_interrupt_handler, +#ifndef XEN .flags = SA_INTERRUPT, +#endif .name = "perfmon" }; +#ifndef XEN static void pfm_alt_save_pmu_state(void *data) { @@ -6580,11 +6923,16 @@ pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) return 0; } EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt); +#endif /* * perfmon initialization routine, called from the initcall() table */ +#ifndef XEN static int init_pfm_fs(void); +#else +#define init_pfm_fs() do {} while(0) +#endif static int __init pfm_probe_pmu(void) @@ -6609,12 +6957,14 @@ found: return 0; } +#ifndef XEN static struct file_operations pfm_proc_fops = { .open = pfm_proc_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; +#endif int __init pfm_init(void) @@ -6684,6 +7034,7 @@ pfm_init(void) return -1; } +#ifndef XEN /* * create /proc/perfmon (mostly for debugging purposes) */ @@ -6702,6 +7053,7 @@ pfm_init(void) * create /proc/sys/kernel/perfmon (for debugging purposes) */ pfm_sysctl_header = register_sysctl_table(pfm_sysctl_root, 0); +#endif /* * initialize all our spinlocks @@ -6768,12 +7120,14 @@ dump_pmu_state(const char *from) return; } +#ifndef XEN printk("CPU%d from %s() current [%d] iip=0x%lx %s\n", this_cpu, from, current->pid, regs->cr_iip, current->comm); +#endif task = GET_PMU_OWNER(); ctx = GET_PMU_CTX(); @@ -6808,6 +7162,7 @@ dump_pmu_state(const char *from) } if (ctx) { +#ifndef XEN printk("->CPU%d ctx_state=%d vaddr=%p addr=%p fd=%d ctx_task=[%d] saved_psr_up=0x%lx\n", this_cpu, ctx->ctx_state, @@ -6816,10 +7171,19 @@ dump_pmu_state(const char *from) ctx->ctx_msgq_head, ctx->ctx_msgq_tail, ctx->ctx_saved_psr_up); +#else + printk("->CPU%d ctx_state=%d vaddr=%p addr=%p saved_psr_up=0x%lx\n", + this_cpu, + ctx->ctx_state, + ctx->ctx_smpl_vaddr, + ctx->ctx_smpl_hdr, + ctx->ctx_saved_psr_up); +#endif } local_irq_restore(flags); } +#ifndef XEN /* * called from process.c:copy_thread(). task is new child. */ @@ -6843,6 +7207,7 @@ pfm_inherit(struct task_struct *task, struct pt_regs *regs) * the psr bits are already set properly in copy_threads() */ } +#endif #else /* !CONFIG_PERFMON */ asmlinkage long sys_perfmonctl (int fd, int cmd, void *arg, int count) @@ -6850,3 +7215,584 @@ sys_perfmonctl (int fd, int cmd, void *arg, int count) return -ENOSYS; } #endif /* CONFIG_PERFMON */ + + +#ifdef XEN +static int xenpfm_context_unload(void); +static int xenpfm_start_stop_locked(int is_start); +DEFINE_PER_CPU(pfm_context_t*, xenpfm_context); + +/* + * note: some functions mask interrupt with this lock held + * so that this lock can't be locked from interrupt handler. + * lock order domlist_lock => xenpfm_context_lock + */ +DEFINE_SPINLOCK(xenpfm_context_lock); + +static int +xenpfm_get_features(XEN_GUEST_HANDLE(pfarg_features_t) req) +{ + pfarg_features_t res; + if (guest_handle_is_null(req)) + return -EFAULT; + + memset(&res, 0, sizeof(res)); + pfm_get_features(NULL, &res, 0, NULL); + if (copy_to_guest(req, &res, 1)) + return -EFAULT; + return 0; +} + +static int +xenpfm_pfarg_is_sane(pfarg_context_t* pfx) +{ + int error; + int ctx_flags; + + error = pfarg_is_sane(NULL, pfx); + if (error) + return error; + + ctx_flags = pfx->ctx_flags; + if (!(ctx_flags & PFM_FL_SYSTEM_WIDE) || + ctx_flags & PFM_FL_NOTIFY_BLOCK || + ctx_flags & PFM_FL_OVFL_NO_MSG) + return -EINVAL; + + /* probably more to add here */ + + return 0; +} + +static int +xenpfm_context_create(XEN_GUEST_HANDLE(pfarg_context_t) req) +{ + int error; + pfarg_context_t kreq; + + int cpu; + pfm_context_t* ctx[NR_CPUS] = {[0 ... (NR_CPUS - 1)] = NULL}; + + if (copy_from_guest(&kreq, req, 1)) { + error = -EINVAL; + goto out; + } + + error = xenpfm_pfarg_is_sane(&kreq); + if (error) + goto out; + + /* XXX fmt */ + for_each_cpu(cpu) { + ctx[cpu] = pfm_context_create(&kreq); + if (ctx[cpu] == NULL) { + error = -ENOMEM; + break; + } + } + if (error) + goto out; + + BUG_ON(in_irq()); + spin_lock(&xenpfm_context_lock); + for_each_cpu(cpu) { + if (per_cpu(xenpfm_context, cpu) != NULL) { + error = -EBUSY; + break; + } + } + for_each_cpu(cpu) { + per_cpu(xenpfm_context, cpu) = ctx[cpu]; + ctx[cpu] = NULL; + } + spin_unlock(&xenpfm_context_lock); + +out: + for_each_cpu(cpu) { + if (ctx[cpu] != NULL) + pfm_context_free(ctx[cpu]); + } + return error; +} + +static int +xenpfm_context_destroy(void) +{ + int cpu; + pfm_context_t* ctx; + unsigned long flags; + unsigned long need_unload; + int error = 0; + +again: + need_unload = 0; + BUG_ON(in_irq()); + spin_lock_irqsave(&xenpfm_context_lock, flags); + for_each_cpu(cpu) { + ctx = per_cpu(xenpfm_context, cpu); + if (ctx == NULL) { + error = -EINVAL; + break; + } + PROTECT_CTX_NOIRQ(ctx); + if (ctx->ctx_state != PFM_CTX_UNLOADED) + need_unload = 1; + } + if (error) { + for_each_cpu(cpu) { + ctx = per_cpu(xenpfm_context, cpu); + if (ctx == NULL) + break; + UNPROTECT_CTX_NOIRQ(per_cpu(xenpfm_context, cpu)); + } + goto out; + } + if (need_unload) { + for_each_cpu(cpu) + UNPROTECT_CTX_NOIRQ(per_cpu(xenpfm_context, cpu)); + spin_unlock_irqrestore(&xenpfm_context_lock, flags); + + error = xenpfm_context_unload(); + if (error) + return error; + goto again; + } + + for_each_cpu(cpu) { + pfm_context_t* ctx = per_cpu(xenpfm_context, cpu); + per_cpu(xenpfm_context, cpu) = NULL; + + /* pfm_close() unlocks spinlock and free the context. */ + error |= pfm_close(ctx); + } +out: + spin_unlock_irqrestore(&xenpfm_context_lock, flags); + return error; +} + +static int +xenpfm_write_pmcs(XEN_GUEST_HANDLE(pfarg_reg_t) req, unsigned long count) +{ + unsigned long i; + int error = 0; + unsigned long flags; + + for (i = 0; i < count; i++) { + pfarg_reg_t kreq; + int cpu; + if (copy_from_guest_offset(&kreq, req, i, 1)) { + error = -EFAULT; + goto out; + } + BUG_ON(in_irq()); + spin_lock_irqsave(&xenpfm_context_lock, flags); + for_each_online_cpu(cpu) { + pfm_context_t* ctx = per_cpu(xenpfm_context, cpu); + PROTECT_CTX_NOIRQ(ctx); + error |= pfm_write_pmcs(ctx, (void *)&kreq, 1, NULL); + UNPROTECT_CTX_NOIRQ(ctx); + } + spin_unlock_irqrestore(&xenpfm_context_lock, flags); + if (error) + break; + } + + /* XXX if is loaded, change all physical cpus pmcs. */ + /* Currently results in error */ +out: + return error; +} + +static int +xenpfm_write_pmds(XEN_GUEST_HANDLE(pfarg_reg_t) req, unsigned long count) +{ + unsigned long i; + int error = 0; + + for (i = 0; i < count; i++) { + pfarg_reg_t kreq; + int cpu; + unsigned long flags; + if (copy_from_guest_offset(&kreq, req, i, 1)) { + error = -EFAULT; + goto out; + } + BUG_ON(in_irq()); + spin_lock_irqsave(&xenpfm_context_lock, flags); + for_each_online_cpu(cpu) { + pfm_context_t* ctx = per_cpu(xenpfm_context, cpu); + PROTECT_CTX_NOIRQ(ctx); + error |= pfm_write_pmds(ctx, &kreq, 1, NULL); + UNPROTECT_CTX_NOIRQ(ctx); + } + spin_unlock_irqrestore(&xenpfm_context_lock, flags); + } + + /* XXX if is loaded, change all physical cpus pmds. */ + /* Currently results in error */ +out: + return error; +} + +struct xenpfm_context_load_arg { + pfarg_load_t* req; + int error[NR_CPUS]; +}; + +static void +xenpfm_context_load_cpu(void* info) +{ + unsigned long flags; + struct xenpfm_context_load_arg* arg = (struct xenpfm_context_load_arg*)info; + pfm_context_t* ctx = __get_cpu_var(xenpfm_context); + PROTECT_CTX(ctx, flags); + arg->error[smp_processor_id()] = pfm_context_load(ctx, arg->req, 0, NULL); + UNPROTECT_CTX(ctx, flags); +} + +static int +xenpfm_context_load(XEN_GUEST_HANDLE(pfarg_load_t) req) +{ + pfarg_load_t kreq; + int cpu; + struct xenpfm_context_load_arg arg; + int error = 0; + + if (copy_from_guest(&kreq, req, 1)) + return -EFAULT; + + arg.req = &kreq; + for_each_online_cpu(cpu) + arg.error[cpu] = 0; + + BUG_ON(in_irq()); + spin_lock(&xenpfm_context_lock); + smp_call_function(&xenpfm_context_load_cpu, &arg, 1, 1); + xenpfm_context_load_cpu(&arg); + spin_unlock(&xenpfm_context_lock); + for_each_online_cpu(cpu) { + if (arg.error[cpu]) { + gdprintk(XENLOG_INFO, "%s: error %d cpu %d\n", + __func__, error, cpu); + error = arg.error[cpu]; + } + } + return 0; +} + + +struct xenpfm_context_unload_arg { + int error[NR_CPUS]; +}; + +static void +xenpfm_context_unload_cpu(void* info) +{ + unsigned long flags; + struct xenpfm_context_unload_arg* arg = (struct xenpfm_context_unload_arg*)info; + pfm_context_t* ctx = __get_cpu_var(xenpfm_context); + PROTECT_CTX(ctx, flags); + arg->error[smp_processor_id()] = pfm_context_unload(ctx, NULL, 0, NULL); + UNPROTECT_CTX(ctx, flags); +} + +static int +xenpfm_context_unload(void) +{ + int cpu; + struct xenpfm_context_unload_arg arg; + int error = 0; + + for_each_online_cpu(cpu) + arg.error[cpu] = 0; + + BUG_ON(in_irq()); + read_lock(&domlist_lock); + spin_lock(&xenpfm_context_lock); + error = xenpfm_start_stop_locked(0); + read_unlock(&domlist_lock); + if (error) { + spin_unlock(&xenpfm_context_lock); + return error; + } + + smp_call_function(&xenpfm_context_unload_cpu, &arg, 1, 1); + xenpfm_context_unload_cpu(&arg); + spin_unlock(&xenpfm_context_lock); + for_each_online_cpu(cpu) { + if (arg.error[cpu]) { + gdprintk(XENLOG_INFO, "%s: error %d cpu %d\n", + __func__, error, cpu); + error = arg.error[cpu]; + } + } + return error; +} + +static int +__xenpfm_start(void) +{ + pfm_context_t* ctx = __get_cpu_var(xenpfm_context); + int state; + int error = 0; + + BUG_ON(local_irq_is_enabled()); + PROTECT_CTX_NOIRQ(ctx); + state = ctx->ctx_state; + if (state != PFM_CTX_LOADED) { + error = -EINVAL; + goto out; + } + + /* now update the local PMU and cpuinfo */ + PFM_CPUINFO_SET(PFM_CPUINFO_DCR_PP); + + /* start monitoring at kernel level */ + pfm_set_psr_pp(); + + /* start monitoring at kernel level */ + pfm_set_psr_up(); + + /* enable dcr pp */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) | IA64_DCR_PP); + ia64_srlz_i(); +out: + UNPROTECT_CTX_NOIRQ(ctx); + return error; +} + +static int +__xenpfm_stop(void) +{ + pfm_context_t* ctx = __get_cpu_var(xenpfm_context); + int state; + int error = 0; + + BUG_ON(local_irq_is_enabled()); + PROTECT_CTX_NOIRQ(ctx); + state = ctx->ctx_state; + if (state != PFM_CTX_LOADED) { + error = -EINVAL; + goto out; + } + + /* + * Update local PMU first + * + * disable dcr pp + */ + ia64_setreg(_IA64_REG_CR_DCR, ia64_getreg(_IA64_REG_CR_DCR) & ~IA64_DCR_PP); + ia64_srlz_i(); + + /* update local cpuinfo */ + PFM_CPUINFO_CLEAR(PFM_CPUINFO_DCR_PP); + + /* stop monitoring, does srlz.i */ + pfm_clear_psr_pp(); + + /* stop monitoring at kernel level */ + pfm_clear_psr_up(); +out: + UNPROTECT_CTX_NOIRQ(ctx); + return error; +} + +int +__xenpfm_start_stop(int is_start) +{ + if (is_start) + return __xenpfm_start(); + else + return __xenpfm_stop(); +} + +struct xenpfm_start_arg { + int is_start; + atomic_t started; + atomic_t finished; + int error[NR_CPUS]; +}; + +static void +xenpfm_start_stop_cpu(void* info) +{ + unsigned long flags; + struct xenpfm_start_arg* arg = (struct xenpfm_start_arg*)info; + + local_irq_save(flags); + atomic_inc(&arg->started); + while (!atomic_read(&arg->finished)) + cpu_relax(); + + arg->error[smp_processor_id()] = __xenpfm_start_stop(arg->is_start); + + atomic_inc(&arg->finished); + local_irq_restore(flags); +} + +static void +xenpfm_start_stop_vcpu(struct vcpu* v, int is_start) +{ + struct pt_regs *regs = vcpu_regs(v); + + if (is_start) { + /* set user level psr.pp for the caller */ + ia64_psr(regs)->pp = 1; + + /* activate monitoring at user level */ + ia64_psr(regs)->up = 1; + + /* don't allow user level control */ + ia64_psr(regs)->sp = 0; + } else { + /* + * stop monitoring in the caller + */ + ia64_psr(regs)->pp = 0; + + /* + * stop monitoring at the user level + */ + ia64_psr(regs)->up = 0; + +#if 0 + /* + * cancel user level control + */ + ia64_psr(regs)->sp = 1; +#endif + } +} + +static int +xenpfm_start_stop_locked(int is_start) +{ + struct xenpfm_start_arg arg; + int cpus = num_online_cpus(); + int cpu; + unsigned long flags; + struct domain* d; + struct vcpu* v; + int error = 0; + + arg.is_start = is_start; + atomic_set(&arg.started, 1); /* 1 for this cpu */ + atomic_set(&arg.finished, 0); + for_each_cpu(cpu) + arg.error[cpu] = 0; + + BUG_ON(!spin_is_locked(&xenpfm_context_lock)); + smp_call_function(&xenpfm_start_stop_cpu, &arg, 1, 0); + local_irq_save(flags); + + while (atomic_read(&arg.started) != cpus) + cpu_relax(); + + for_each_domain(d) { + for_each_vcpu(d, v) + xenpfm_start_stop_vcpu(v, is_start); + } + + arg.error[smp_processor_id()] = __xenpfm_start_stop(is_start); + atomic_inc(&arg.finished); + + while (atomic_read(&arg.finished) != cpus) + cpu_relax(); + local_irq_restore(flags); + + for_each_online_cpu(cpu) { + if (!arg.error[cpu]) { + gdprintk(XENLOG_INFO, "%s: cpu %d error %d\n", + __func__, cpu, arg.error[cpu]); + error = arg.error[cpu]; + } + } + return error; +} + +static int +xenpfm_start_stop(int is_start) +{ + int error; + + BUG_ON(in_irq()); + read_lock(&domlist_lock); + spin_lock(&xenpfm_context_lock); + error =xenpfm_start_stop_locked(is_start); + spin_unlock(&xenpfm_context_lock); + read_unlock(&domlist_lock); + + return error; +} + +#define NONPRIV_OP(cmd) (((cmd) == PFM_GET_FEATURES)) + +int +do_perfmon_op(unsigned long cmd, + XEN_GUEST_HANDLE(void) arg1, unsigned long count) +{ + unsigned long error = 0; + + if (!NONPRIV_OP(cmd) && current->domain != xenoprof_primary_profiler) { + gdprintk(XENLOG_INFO, "xen perfmon: " + "dom %d denied privileged operation %ld\n", + current->domain->domain_id, cmd); + return -EPERM; + } + switch (cmd) { + case PFM_GET_FEATURES: + error = xenpfm_get_features(guest_handle_cast(arg1, pfarg_features_t)); + break; + + case PFM_CREATE_CONTEXT: + error = xenpfm_context_create(guest_handle_cast(arg1, pfarg_context_t)); + break; + case PFM_DESTROY_CONTEXT: + error = xenpfm_context_destroy(); + break; + + case PFM_WRITE_PMCS: + error = xenpfm_write_pmcs(guest_handle_cast(arg1, pfarg_reg_t), count); + break; + case PFM_WRITE_PMDS: + error = xenpfm_write_pmds(guest_handle_cast(arg1, pfarg_reg_t), count); + break; + case PFM_READ_PMDS: + error = -ENOSYS; + break; + case PFM_GET_PMC_RESET_VAL: + error = -ENOSYS; + break; + + case PFM_LOAD_CONTEXT: + error = xenpfm_context_load(guest_handle_cast(arg1, pfarg_load_t)); + break; + case PFM_UNLOAD_CONTEXT: + error = xenpfm_context_unload(); + break; + + case PFM_START: + error = xenpfm_start_stop(1); + break; + case PFM_STOP: + error = xenpfm_start_stop(0); + break; + case PFM_RESTART: + error = -ENOSYS; + break; + + case PFM_DEBUG: + error = -ENOSYS; + break; + + case PFM_ENABLE: + case PFM_DISABLE: + case PFM_PROTECT_CONTEXT: + case PFM_UNPROTECT_CONTEXT: + default: + error = -EINVAL; + break; + } + return error; +} +#endif diff --git a/xen/arch/ia64/linux-xen/perfmon_default_smpl.c b/xen/arch/ia64/linux-xen/perfmon_default_smpl.c index 344941db0a..f10a5a6f0a 100644 --- a/xen/arch/ia64/linux-xen/perfmon_default_smpl.c +++ b/xen/arch/ia64/linux-xen/perfmon_default_smpl.c @@ -16,9 +16,15 @@ #include #include +#ifndef XEN MODULE_AUTHOR("Stephane Eranian "); MODULE_DESCRIPTION("perfmon default sampling format"); MODULE_LICENSE("GPL"); +#endif + +#ifdef XEN +#define pid vcpu_id +#endif #define DEFAULT_DEBUG 1 @@ -157,7 +163,9 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct * system-wide: * - this is not necessarily the task controlling the session */ +#ifndef XEN ent->pid = current->pid; +#endif ent->ovfl_pmd = ovfl_pmd; ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val; @@ -169,7 +177,9 @@ default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct ent->tstamp = stamp; ent->cpu = smp_processor_id(); ent->set = arg->active_set; +#ifndef XEN ent->tgid = current->tgid; +#endif /* * selectively store PMDs in increasing index number @@ -263,6 +273,7 @@ static pfm_buffer_fmt_t default_fmt={ .fmt_exit = default_exit, }; +#ifndef XEN static int __init pfm_default_smpl_init_module(void) { @@ -282,6 +293,7 @@ pfm_default_smpl_init_module(void) return ret; } +#endif static void __exit pfm_default_smpl_cleanup_module(void) @@ -292,6 +304,8 @@ pfm_default_smpl_cleanup_module(void) printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret); } +#ifndef XEN module_init(pfm_default_smpl_init_module); module_exit(pfm_default_smpl_cleanup_module); +#endif diff --git a/xen/arch/ia64/linux/Makefile b/xen/arch/ia64/linux/Makefile index 926fc501df..6acc02583d 100644 --- a/xen/arch/ia64/linux/Makefile +++ b/xen/arch/ia64/linux/Makefile @@ -22,6 +22,7 @@ obj-y += __divdi3.o obj-y += __udivdi3.o obj-y += __moddi3.o obj-y += __umoddi3.o +obj-y += carta_random.o ## variants of divide/modulo ## see files in xen/arch/ia64/linux/lib (linux/arch/ia64/lib) diff --git a/xen/arch/ia64/xen/Makefile b/xen/arch/ia64/xen/Makefile index 87f22f0966..8eee2940e1 100644 --- a/xen/arch/ia64/xen/Makefile +++ b/xen/arch/ia64/xen/Makefile @@ -1,3 +1,5 @@ +subdir-y += oprofile + obj-y += acpi.o obj-y += dom0_ops.o obj-y += domain.o diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index 8d53e43ff3..affcafceaa 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -343,6 +343,12 @@ do_dom0vp_op(unsigned long cmd, case IA64_DOM0VP_expose_p2m: ret = dom0vp_expose_p2m(d, arg0, arg1, arg2, arg3); break; + case IA64_DOM0VP_perfmon: { + XEN_GUEST_HANDLE(void) hnd; + set_xen_guest_handle(hnd, (void*)arg1); + ret = do_perfmon_op(arg0, hnd, arg2); + break; + } default: ret = -1; printk("unknown dom0_vp_op 0x%lx\n", cmd); diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 11bd8b9fcf..0be27db053 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -48,6 +48,7 @@ #include #include #include +#include unsigned long dom0_size = 512*1024*1024; @@ -231,11 +232,35 @@ void continue_running(struct vcpu *same) /* nothing to do */ } +#ifdef CONFIG_PERFMON +static int pal_halt = 1; +static int can_do_pal_halt = 1; + +static int __init nohalt_setup(char * str) +{ + pal_halt = can_do_pal_halt = 0; + return 1; +} +__setup("nohalt", nohalt_setup); + +void +update_pal_halt_status(int status) +{ + can_do_pal_halt = pal_halt && status; +} +#else +#define can_do_pal_halt (1) +#endif + static void default_idle(void) { local_irq_disable(); - if ( !softirq_pending(smp_processor_id()) ) - safe_halt(); + if ( !softirq_pending(smp_processor_id()) ) { + if (can_do_pal_halt) + safe_halt(); + else + cpu_relax(); + } local_irq_enable(); } @@ -628,6 +653,9 @@ void domain_relinquish_resources(struct domain *d) if (d->arch.is_vti && d->arch.sal_data) xfree(d->arch.sal_data); + + /* Free page used by xen oprofile buffer */ + free_xenoprof_pages(d); } unsigned long diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index ba4daba297..58c6a41115 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -68,7 +68,7 @@ const hypercall_t ia64_hypercall_table[NR_hypercalls] = (hypercall_t)do_ni_hypercall, /* do_nmi_op */ (hypercall_t)do_sched_op, (hypercall_t)do_callback_op, /* */ /* 30 */ - (hypercall_t)do_ni_hypercall, /* */ + (hypercall_t)do_xenoprof_op, /* */ (hypercall_t)do_event_channel_op, (hypercall_t)do_physdev_op, (hypercall_t)do_hvm_op, /* */ diff --git a/xen/arch/ia64/xen/oprofile/Makefile b/xen/arch/ia64/xen/oprofile/Makefile new file mode 100644 index 0000000000..826b99b756 --- /dev/null +++ b/xen/arch/ia64/xen/oprofile/Makefile @@ -0,0 +1 @@ +obj-y += perfmon.o xenoprof.o diff --git a/xen/arch/ia64/xen/oprofile/perfmon.c b/xen/arch/ia64/xen/oprofile/perfmon.c index b7975a469f..3a26a04dd9 100644 --- a/xen/arch/ia64/xen/oprofile/perfmon.c +++ b/xen/arch/ia64/xen/oprofile/perfmon.c @@ -1,3 +1,25 @@ +/****************************************************************************** + * perfmon.c for xenoprof + * This is based linux/arch/ia64/oprofile/perfmon.c, but heavily rewritten. + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ /** * @file perfmon.c * @@ -7,94 +29,172 @@ * @author John Levon */ -#include -#include -#include -#include +#include +#include +#include +#include #include #include -#include +// XXX move them to an appropriate header file +extern void xenoprof_log_event(struct vcpu *vcpu, + unsigned long eip, int mode, int event); +extern int is_active(struct domain *d); + +static int allow_virq; static int allow_ints; static int -perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, - struct pt_regs *regs, unsigned long stamp) +xenoprof_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, + struct pt_regs *regs, unsigned long stamp) { - int event = arg->pmd_eventid; + unsigned long ip = regs->cr_iip; + int event = arg->pmd_eventid; - arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; + arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; + if (!allow_virq || !allow_ints) + return 0; - /* the owner of the oprofile event buffer may have exited - * without perfmon being shutdown (e.g. SIGSEGV) - */ - if (allow_ints) - oprofile_add_sample(regs, event); - return 0; + xenoprof_log_event(current, ip, xenoprofile_get_mode(task, regs), event); + + // send VIRQ_XENOPROF + if (is_active(current->domain) && !ring_0(regs)) + send_guest_vcpu_virq(current, VIRQ_XENOPROF); + + return 0; } +// same as linux OPROFILE_FMT_UUID +#define XENOPROF_FMT_UUID { \ + 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } -static int perfmon_start(void) +static pfm_buffer_fmt_t xenoprof_fmt = { + .fmt_name = "xenoprof_format", + .fmt_uuid = XENOPROF_FMT_UUID, + .fmt_handler = xenoprof_handler, +}; + +static char * get_cpu_type(void) +{ + __u8 family = local_cpu_data->family; + + switch (family) { + case 0x07: + return "ia64/itanium"; + case 0x1f: + return "ia64/itanium2"; + default: + return "ia64/ia64"; + } +} + +static int using_xenoprof; + +int __init +xenprof_perfmon_init(void) +{ + int ret = pfm_register_buffer_fmt(&xenoprof_fmt); + if (ret) + return -ENODEV; + using_xenoprof = 1; + printk("xenoprof: using perfmon.\n"); + return 0; +} +__initcall(xenprof_perfmon_init); + +#ifdef notyet +void xenoprof_perfmon_exit(void) +{ + if (!using_xenoprof) + return; + + pfm_unregister_buffer_fmt(xenoprof_fmt.fmt_uuid); +} +__exitcall(xenoprof_perfmon_exit); +#endif + +/////////////////////////////////////////////////////////////////////////// +// glue methods for xenoprof and perfmon. +int +xenoprof_arch_init(int *num_events, int *is_primary, char *cpu_type) +{ + *num_events = 0; + strncpy(cpu_type, get_cpu_type(), XENOPROF_CPU_TYPE_SIZE - 1); + cpu_type[XENOPROF_CPU_TYPE_SIZE - 1] = '\0'; + + *is_primary = 0; + if (xenoprof_primary_profiler == NULL) { + /* For now, only dom0 can be the primary profiler */ + if (current->domain->domain_id == 0) { + *is_primary = 1; + } + } else if (xenoprof_primary_profiler == current->domain) + *is_primary = 1; + return 0; +} + +int +xenoprof_arch_reserve_counters(void) +{ + // perfmon takes care + return 0; +} + +int +xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg) +{ + return -ENOSYS; +} + +int +xenoprof_arch_setup_events(void) +{ + // perfmon takes care + return 0; +} + +//XXX SMP: sync by IPI? +int +xenoprof_arch_enable_virq(void) +{ + allow_virq = 1; + return 0; +} + +//XXX SMP: sync by IPI? +int +xenoprof_arch_start(void) { allow_ints = 1; - return 0; + return 0; } - -static void perfmon_stop(void) +//XXX SMP: sync by IPI? +void +xenoprof_arch_stop(void) { allow_ints = 0; } - -#define OPROFILE_FMT_UUID { \ - 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c } - -static pfm_buffer_fmt_t oprofile_fmt = { - .fmt_name = "oprofile_format", - .fmt_uuid = OPROFILE_FMT_UUID, - .fmt_handler = perfmon_handler, -}; - - -static char * get_cpu_type(void) +//XXX SMP: sync by IPI? +void +xenoprof_arch_disable_virq(void) { - __u8 family = local_cpu_data->family; - - switch (family) { - case 0x07: - return "ia64/itanium"; - case 0x1f: - return "ia64/itanium2"; - default: - return "ia64/ia64"; - } + allow_virq = 0; } - -/* all the ops are handled via userspace for IA64 perfmon */ - -static int using_perfmon; - -int perfmon_init(struct oprofile_operations * ops) +void +xenoprof_arch_release_counters(void) { - int ret = pfm_register_buffer_fmt(&oprofile_fmt); - if (ret) - return -ENODEV; - - ops->cpu_type = get_cpu_type(); - ops->start = perfmon_start; - ops->stop = perfmon_stop; - using_perfmon = 1; - printk(KERN_INFO "oprofile: using perfmon.\n"); - return 0; + // perfmon takes care } - -void perfmon_exit(void) -{ - if (!using_perfmon) - return; - - pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); -} +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/ia64/xen/oprofile/xenoprof.c b/xen/arch/ia64/xen/oprofile/xenoprof.c new file mode 100644 index 0000000000..a1dd5128d4 --- /dev/null +++ b/xen/arch/ia64/xen/oprofile/xenoprof.c @@ -0,0 +1,56 @@ +/****************************************************************************** + * xenoprof.c + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +int +xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs) +{ + int mode = 0; + + // mode + // 0: user, 1: kernel, 2: xen + // Xen/IA64 uses ring2 for kernel, and doesn't use ring1. + if (ring_2(regs)) + mode = 1; + else if (ring_0(regs)) + mode = 2; + else if (ring_1(regs)) { + gdprintk(XENLOG_ERR, "%s:%d ring1 is used!\n", __func__, __LINE__); + mode = 1;// fall back to kernel mode. + } + + return mode; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 05910e4310..bb71eb8c12 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -125,6 +125,7 @@ extern char _end[]; /* standard ELF symbol */ // from include/asm-ia64/smp.h #define get_cpu() smp_processor_id() #define put_cpu() do {} while(0) +#define put_cpu_no_resched() do{} while (0) // needed for common/dom0_ops.c until hyperthreading is supported #ifdef CONFIG_SMP @@ -166,6 +167,8 @@ extern int smp_num_siblings; #define ____cacheline_aligned_in_smp ____cacheline_aligned #endif +#define CONFIG_PERFMON + #ifndef __ASSEMBLY__ #include "asm/types.h" // for u64 #include "linux/linkage.h" // for asmlinkage which is used by diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index cfe7c5e9a3..251ffda02a 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -211,6 +211,10 @@ struct arch_vcpu { #define IO_PORTS_PADDR 0x00000ffffc000000UL #define IO_PORTS_SIZE 0x0000000004000000UL +int +do_perfmon_op(unsigned long cmd, + XEN_GUEST_HANDLE(void) arg1, unsigned long arg2); + #endif /* __ASM_DOMAIN_H__ */ /* diff --git a/xen/include/asm-ia64/linux-xen/asm/perfmon.h b/xen/include/asm-ia64/linux-xen/asm/perfmon.h index 7f3333dd00..23dec44bc3 100644 --- a/xen/include/asm-ia64/linux-xen/asm/perfmon.h +++ b/xen/include/asm-ia64/linux-xen/asm/perfmon.h @@ -6,6 +6,14 @@ #ifndef _ASM_IA64_PERFMON_H #define _ASM_IA64_PERFMON_H +#ifdef XEN +#include +#ifndef pt_regs +#define pt_regs cpu_user_regs +#endif +struct cpu_user_regs; +#endif + /* * perfmon comamnds supported on all CPU models */ diff --git a/xen/include/asm-ia64/xenoprof.h b/xen/include/asm-ia64/xenoprof.h new file mode 100644 index 0000000000..b8b1e602d9 --- /dev/null +++ b/xen/include/asm-ia64/xenoprof.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * asm-ia64/xenoprof.h + * xenoprof ia64 arch specific header file + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_XENOPROF_H__ +#define __ASM_XENOPROF_H__ + +int xenoprof_arch_init(int *num_events, int *is_primary, char *cpu_type); +int xenoprof_arch_reserve_counters(void); +int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg); +int xenoprof_arch_setup_events(void); +int xenoprof_arch_enable_virq(void); +int xenoprof_arch_start(void); +void xenoprof_arch_stop(void); +void xenoprof_arch_disable_virq(void); +void xenoprof_arch_release_counters(void); + +struct vcpu; +struct cpu_user_regs; +int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs); + +#define xenoprof_shared_gmfn(d, gmaddr, maddr) \ + assign_domain_page((d), (gmaddr), (maddr)); + +static inline int +ring(const struct pt_regs* regs) +{ + return ((struct ia64_psr*)(&(regs)->cr_ipsr))->cpl; +} +#define ring_0(r) (ring(r) == 0) +#define ring_1(r) (ring(r) == 1) +#define ring_2(r) (ring(r) == 2) +#define ring_3(r) (ring(r) == 3) + +#endif /* __ASM_XENOPROF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index 9265839ded..8125eacebb 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -376,6 +376,9 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); /* expose the p2m table into domain */ #define IA64_DOM0VP_expose_p2m 7 +/* xen perfmon */ +#define IA64_DOM0VP_perfmon 8 + // flags for page assignement to pseudo physical address space #define _ASSIGN_readonly 0 #define ASSIGN_readonly (1UL << _ASSIGN_readonly) @@ -462,6 +465,25 @@ struct xen_ia64_boot_param { (((unsigned long)(addr) & XENCOMM_INLINE_MASK) == XENCOMM_INLINE_FLAG) #define XENCOMM_INLINE_ADDR(addr) \ ((unsigned long)(addr) & ~XENCOMM_INLINE_MASK) + +/* xen perfmon */ +#ifdef XEN +#ifndef __ASSEMBLY__ +#ifndef _ASM_IA64_PERFMON_H + +#include // asm/perfmon.h requires struct list_head +#include +// for PFM_xxx and pfarg_features_t, pfarg_context_t, pfarg_reg_t, pfarg_load_t + +#endif /* _ASM_IA64_PERFMON_H */ + +DEFINE_XEN_GUEST_HANDLE(pfarg_features_t); +DEFINE_XEN_GUEST_HANDLE(pfarg_context_t); +DEFINE_XEN_GUEST_HANDLE(pfarg_reg_t); +DEFINE_XEN_GUEST_HANDLE(pfarg_load_t); +#endif /* __ASSEMBLY__ */ +#endif /* XEN */ + #endif /* __HYPERVISOR_IF_IA64_H__ */ /* From 0d2fbb95063ed71d61f60772a8b5634087c8d146 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 28 Nov 2006 22:54:24 -0700 Subject: [PATCH 048/282] [IA64] xenoprof linux/ia64 part Signed-off-by: Isaku Yamahata --- .../arch/ia64/kernel/perfmon.c | 90 +++++++++++ .../arch/ia64/oprofile/Makefile | 4 + .../arch/ia64/oprofile/init.c | 14 ++ .../arch/ia64/oprofile/oprofile_perfmon.h | 30 ++++ .../arch/ia64/oprofile/perfmon.c | 35 ++++- .../arch/ia64/oprofile/xenoprof.c | 142 ++++++++++++++++++ .../arch/ia64/xen/hypervisor.c | 52 +++++++ .../arch/ia64/xen/xcom_hcall.c | 66 ++++++++ .../arch/ia64/xen/xcom_mini.c | 99 ++++++++++++ .../include/asm-ia64/hypercall.h | 21 +++ .../include/asm-ia64/xen/xcom_hcall.h | 18 +++ .../include/asm-ia64/xenoprof.h | 48 ++++++ 12 files changed, 611 insertions(+), 8 deletions(-) create mode 100644 linux-2.6-xen-sparse/arch/ia64/oprofile/oprofile_perfmon.h create mode 100644 linux-2.6-xen-sparse/arch/ia64/oprofile/xenoprof.c create mode 100644 linux-2.6-xen-sparse/include/asm-ia64/xenoprof.h diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c b/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c index 9b42b02b85..35e08b5383 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c @@ -53,6 +53,28 @@ #include #ifdef CONFIG_PERFMON +#ifdef CONFIG_XEN +//#include +#include + +static int xenoprof_is_primary = 0; +#define init_xenoprof_primary(is_primary) (xenoprof_is_primary = (is_primary)) +#define is_xenoprof_primary() (xenoprof_is_primary) +#define XEN_NOT_SUPPORTED_YET \ + do { \ + if (is_running_on_xen()) { \ + printk("%s is not supported yet under xen.\n", \ + __func__); \ + return -ENOSYS; \ + } \ + } while (0) +#else +#define init_xenoprof_primary(is_primary) do { } while (0) +#define is_xenoprof_primary() (0) +#define XEN_NOT_SUPPORTED_YET do { } while (0) +#define HYPERVISOR_perfmon_op(cmd, arg, count) do { } while (0) +#endif + /* * perfmon context state */ @@ -1515,6 +1537,7 @@ pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos) ssize_t ret; unsigned long flags; DECLARE_WAITQUEUE(wait, current); + XEN_NOT_SUPPORTED_YET; if (PFM_IS_FILE(filp) == 0) { printk(KERN_ERR "perfmon: pfm_poll: bad magic [%d]\n", current->pid); return -EINVAL; @@ -2113,6 +2136,15 @@ doit: */ if (free_possible) pfm_context_free(ctx); + if (is_running_on_xen()) { + if (is_xenoprof_primary()) { + int ret = HYPERVISOR_perfmon_op(PFM_DESTROY_CONTEXT, + NULL, 0); + if (ret) + printk("%s:%d PFM_DESTROY_CONTEXT hypercall " + "failed\n", __func__, __LINE__); + } + } return 0; } @@ -2736,6 +2768,23 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg */ pfm_reset_pmu_state(ctx); + if (is_running_on_xen()) { + /* + * kludge to get xenoprof.is_primary. + * XENOPROF_init/ia64 is nop. so it is safe to call it here. + */ + struct xenoprof_init init; + ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init); + if (ret) + goto buffer_error; + init_xenoprof_primary(init.is_primary); + + if (is_xenoprof_primary()) { + ret = HYPERVISOR_perfmon_op(PFM_CREATE_CONTEXT, arg, 0); + if (ret) + goto buffer_error; + } + } return 0; buffer_error: @@ -2872,6 +2921,12 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) pfm_reg_check_t wr_func; #define PFM_CHECK_PMC_PM(x, y, z) ((x)->ctx_fl_system ^ PMC_PM(y, z)) + if (is_running_on_xen()) { + if (is_xenoprof_primary()) + return HYPERVISOR_perfmon_op(PFM_WRITE_PMCS, + arg, count); + return 0; + } state = ctx->ctx_state; is_loaded = state == PFM_CTX_LOADED ? 1 : 0; is_system = ctx->ctx_fl_system; @@ -3112,6 +3167,12 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) int ret = -EINVAL; pfm_reg_check_t wr_func; + if (is_running_on_xen()) { + if (is_xenoprof_primary()) + return HYPERVISOR_perfmon_op(PFM_WRITE_PMDS, + arg, count); + return 0; + } state = ctx->ctx_state; is_loaded = state == PFM_CTX_LOADED ? 1 : 0; @@ -3309,6 +3370,7 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) int is_loaded, is_system, is_counting, expert_mode; int ret = -EINVAL; pfm_reg_check_t rd_func; + XEN_NOT_SUPPORTED_YET; /* * access is possible when loaded only for @@ -3560,6 +3622,7 @@ pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) pfm_ovfl_ctrl_t rst_ctrl; int state, is_system; int ret = 0; + XEN_NOT_SUPPORTED_YET; state = ctx->ctx_state; fmt = ctx->ctx_buf_fmt; @@ -3709,6 +3772,7 @@ static int pfm_debug(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { unsigned int m = *(unsigned int *)arg; + XEN_NOT_SUPPORTED_YET; pfm_sysctl.debug = m == 0 ? 0 : 1; @@ -3979,6 +4043,8 @@ pfm_get_features(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { pfarg_features_t *req = (pfarg_features_t *)arg; + if (is_running_on_xen()) + return HYPERVISOR_perfmon_op(PFM_GET_FEATURES, &arg, 0); req->ft_version = PFM_VERSION; return 0; } @@ -3990,6 +4056,12 @@ pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) struct task_struct *task = PFM_CTX_TASK(ctx); int state, is_system; + if (is_running_on_xen()) { + if (is_xenoprof_primary()) + return HYPERVISOR_perfmon_op(PFM_STOP, NULL, 0); + return 0; + } + state = ctx->ctx_state; is_system = ctx->ctx_fl_system; @@ -4078,6 +4150,12 @@ pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) struct pt_regs *tregs; int state, is_system; + if (is_running_on_xen()) { + XENPERFMON_PRINTD("PFM_START\n"); + if (is_xenoprof_primary()) + return HYPERVISOR_perfmon_op(PFM_START, NULL, 0); + return 0; + } state = ctx->ctx_state; is_system = ctx->ctx_fl_system; @@ -4160,6 +4238,7 @@ pfm_get_pmc_reset(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs unsigned int cnum; int i; int ret = -EINVAL; + XEN_NOT_SUPPORTED_YET; for (i = 0; i < count; i++, req++) { @@ -4218,6 +4297,11 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) int ret = 0; int state, is_system, set_dbregs = 0; + if (is_running_on_xen()) { + if (is_xenoprof_primary()) + return HYPERVISOR_perfmon_op(PFM_LOAD_CONTEXT, arg, 0); + return 0; + } state = ctx->ctx_state; is_system = ctx->ctx_fl_system; /* @@ -4466,6 +4550,12 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg int prev_state, is_system; int ret; + if (is_running_on_xen()) { + if (is_xenoprof_primary()) + return HYPERVISOR_perfmon_op(PFM_UNLOAD_CONTEXT, + NULL, 0); + return 0; + } DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); prev_state = ctx->ctx_state; diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile b/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile index aad27a718e..555d4a9d7a 100644 --- a/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/Makefile @@ -8,3 +8,7 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \ oprofile-y := $(DRIVER_OBJS) init.o backtrace.o oprofile-$(CONFIG_PERFMON) += perfmon.o +ifeq ($(CONFIG_XEN), y) +oprofile-$(CONFIG_PERFMON) += xenoprof.o \ + ../../../drivers/xen/xenoprof/xenoprofile.o +endif diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c b/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c index 125a602a66..f218b7eb45 100644 --- a/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/init.c @@ -11,6 +11,7 @@ #include #include #include +#include "oprofile_perfmon.h" extern int perfmon_init(struct oprofile_operations * ops); extern void perfmon_exit(void); @@ -20,6 +21,13 @@ int __init oprofile_arch_init(struct oprofile_operations * ops) { int ret = -ENODEV; + if (is_running_on_xen()) { + ret = xen_perfmon_init(); + if (ret) + return ret; + return xenoprofile_init(ops); + } + #ifdef CONFIG_PERFMON /* perfmon_init() can fail, but we have no way to report it */ ret = perfmon_init(ops); @@ -32,6 +40,12 @@ int __init oprofile_arch_init(struct oprofile_operations * ops) void oprofile_arch_exit(void) { + if (is_running_on_xen()) { + xenoprofile_exit(); + xen_perfmon_exit(); + return; + } + #ifdef CONFIG_PERFMON perfmon_exit(); #endif diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/oprofile_perfmon.h b/linux-2.6-xen-sparse/arch/ia64/oprofile/oprofile_perfmon.h new file mode 100644 index 0000000000..14f1677aea --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/oprofile_perfmon.h @@ -0,0 +1,30 @@ +#ifndef OPROFILE_PERFMON_H +#define OPROFILE_PERFMON_H + +#include + +#ifdef CONFIG_PERFMON +int __perfmon_init(void); +void __perfmon_exit(void); +int perfmon_start(void); +void perfmon_stop(void); +#else +#define __perfmon_init() (-ENOSYS) +#define __perfmon_exit() do {} while (0) +#endif /* CONFIG_PERFMON */ + +#ifdef CONFIG_XEN +#define STATIC_IF_NO_XEN /* nothing */ +#define xen_perfmon_init() __perfmon_init() +#define xen_perfmon_exit() __perfmon_exit() +extern int xenoprofile_init(struct oprofile_operations * ops); +extern void xenoprofile_exit(void); +#else +#define STATIC_IF_NO_XEN static +#define xen_perfmon_init() (-ENOSYS) +#define xen_perfmon_exit() do {} while (0) +#define xenoprofile_init() (-ENOSYS) +#define xenoprofile_exit() do {} while (0) +#endif /* CONFIG_XEN */ + +#endif /* OPROFILE_PERFMON_H */ diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c b/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c index b7975a469f..cd2a002994 100644 --- a/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/perfmon.c @@ -14,6 +14,7 @@ #include #include #include +#include "oprofile_perfmon.h" static int allow_ints; @@ -34,14 +35,16 @@ perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, } -static int perfmon_start(void) +STATIC_IF_NO_XEN +int perfmon_start(void) { allow_ints = 1; return 0; } -static void perfmon_stop(void) +STATIC_IF_NO_XEN +void perfmon_stop(void) { allow_ints = 0; } @@ -76,16 +79,35 @@ static char * get_cpu_type(void) static int using_perfmon; -int perfmon_init(struct oprofile_operations * ops) +STATIC_IF_NO_XEN +int __perfmon_init(void) { int ret = pfm_register_buffer_fmt(&oprofile_fmt); if (ret) return -ENODEV; + using_perfmon = 1; + return 0; +} + +STATIC_IF_NO_XEN +void __perfmon_exit(void) +{ + if (!using_perfmon) + return; + + pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); +} + +int perfmon_init(struct oprofile_operations * ops) +{ + int ret = __perfmon_init(); + if (ret) + return -ENODEV; + ops->cpu_type = get_cpu_type(); ops->start = perfmon_start; ops->stop = perfmon_stop; - using_perfmon = 1; printk(KERN_INFO "oprofile: using perfmon.\n"); return 0; } @@ -93,8 +115,5 @@ int perfmon_init(struct oprofile_operations * ops) void perfmon_exit(void) { - if (!using_perfmon) - return; - - pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid); + __perfmon_exit(); } diff --git a/linux-2.6-xen-sparse/arch/ia64/oprofile/xenoprof.c b/linux-2.6-xen-sparse/arch/ia64/oprofile/xenoprof.c new file mode 100644 index 0000000000..998be3e66b --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/oprofile/xenoprof.c @@ -0,0 +1,142 @@ +/****************************************************************************** + * xenoprof ia64 specific part + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include + +#include +#include +#include +#include + +#include "oprofile_perfmon.h" + +void __init xenoprof_arch_init_counter(struct xenoprof_init *init) +{ + init->num_events = 0; /* perfmon manages. */ +} + +void xenoprof_arch_counter(void) +{ + /* nothing. perfmon does. */ +} + +void xenoprof_arch_start(void) +{ + perfmon_start(); +} + +void xenoprof_arch_stop(void) +{ + perfmon_stop(); +} + +/* XXX move them to an appropriate header file. */ +struct resource* xen_ia64_allocate_resource(unsigned long size); +void xen_ia64_release_resource(struct resource* res); +void xen_ia64_unmap_resource(struct resource* res); + +struct resource* +xenoprof_ia64_allocate_resource(int32_t max_samples) +{ + unsigned long bufsize; + + /* XXX add hypercall to get bufsize? */ + /* this value is taken from alloc_xenoprof_struct(). */ +#if 0 + bufsize = NR_CPUS * (sizeof(struct xenoprof_buf) + + (max_samples - 1) * sizeof(struct event_log)); + bufsize = PAGE_ALIGN(bufsize) + PAGE_SIZE; +#else +#define MAX_OPROF_SHARED_PAGES 32 + bufsize = (MAX_OPROF_SHARED_PAGES + 1) * PAGE_SIZE; +#endif + return xen_ia64_allocate_resource(bufsize); +} + +void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer* sbuf) +{ + if (sbuf->buffer) { + xen_ia64_unmap_resource(sbuf->arch.res); + sbuf->buffer = NULL; + sbuf->arch.res = NULL; + } +} + +int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer* get_buffer, + struct xenoprof_shared_buffer* sbuf) +{ + int ret; + struct resource* res; + + sbuf->buffer = NULL; + sbuf->arch.res = NULL; + + res = xenoprof_ia64_allocate_resource(get_buffer->max_samples); + if (IS_ERR(res)) + return PTR_ERR(res); + + get_buffer->buf_gmaddr = res->start; + + ret = HYPERVISOR_xenoprof_op(XENOPROF_get_buffer, get_buffer); + if (ret) { + xen_ia64_release_resource(res); + return ret; + } + + BUG_ON((res->end - res->start + 1) < + get_buffer->bufsize * get_buffer->nbuf); + + sbuf->buffer = __va(res->start); + sbuf->arch.res = res; + + return ret; +} + +int xenoprof_arch_set_passive(struct xenoprof_passive* pdomain, + struct xenoprof_shared_buffer* sbuf) +{ + int ret; + struct resource* res; + + sbuf->buffer = NULL; + sbuf->arch.res = NULL; + + res = xenoprof_ia64_allocate_resource(pdomain->max_samples); + if (IS_ERR(res)) + return PTR_ERR(res); + + pdomain->buf_gmaddr = res->start; + + ret = HYPERVISOR_xenoprof_op(XENOPROF_set_passive, pdomain); + if (ret) { + xen_ia64_release_resource(res); + return ret; + } + + BUG_ON((res->end - res->start + 1) < pdomain->bufsize * pdomain->nbuf); + + sbuf->buffer = __va(res->start); + sbuf->arch.res = res; + + return ret; +} diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c index 2a85caa0d5..98b5982e2a 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c @@ -1050,3 +1050,55 @@ EXPORT_SYMBOL_GPL(p2m_convert_max_pfn); EXPORT_SYMBOL_GPL(p2m_pte); EXPORT_SYMBOL_GPL(p2m_phystomach); #endif + +/////////////////////////////////////////////////////////////////////////// +// for xenoprof + +struct resource* +xen_ia64_allocate_resource(unsigned long size) +{ + struct resource* res; + int error; + + res = kmalloc(sizeof(*res), GFP_KERNEL); + if (res == NULL) + return ERR_PTR(-ENOMEM); + + res->name = "Xen"; + res->flags = IORESOURCE_MEM; + error = allocate_resource(&iomem_resource, res, PAGE_ALIGN(size), + privcmd_resource_min, privcmd_resource_max, + IA64_GRANULE_SIZE, NULL, NULL); + if (error) { + kfree(res); + return ERR_PTR(error); + } + return res; +} +EXPORT_SYMBOL_GPL(xen_ia64_allocate_resource); + +void +xen_ia64_release_resource(struct resource* res) +{ + release_resource(res); + kfree(res); +} +EXPORT_SYMBOL_GPL(xen_ia64_release_resource); + +void +xen_ia64_unmap_resource(struct resource* res) +{ + unsigned long gpfn = res->start >> PAGE_SHIFT; + unsigned long nr_pages = (res->end - res->start) >> PAGE_SHIFT; + unsigned long i; + + for (i = 0; i < nr_pages; i++) { + int error = HYPERVISOR_zap_physmap(gpfn + i, 0); + if (error) + printk(KERN_ERR + "%s:%d zap_phsymap failed %d gpfn %lx\n", + __func__, __LINE__, error, gpfn + i); + } + xen_ia64_release_resource(res); +} +EXPORT_SYMBOL_GPL(xen_ia64_unmap_resource); diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c index fda0a45ec5..ec46b84037 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c @@ -32,10 +32,12 @@ #include #include #include +#include #include #include #include #include +#include /* Xencomm notes: * This file defines hypercalls to be used by xencomm. The hypercalls simply @@ -301,3 +303,67 @@ xencomm_hypercall_suspend(unsigned long srec) return xencomm_arch_hypercall_suspend(xencomm_create_inline(&arg)); } + +#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) +int +xencomm_hypercall_xenoprof_op(int op, void *arg) +{ + switch (op) { + case XENOPROF_init: + case XENOPROF_set_active: + case XENOPROF_set_passive: + case XENOPROF_counter: + case XENOPROF_get_buffer: + break; + + case XENOPROF_reset_active_list: + case XENOPROF_reset_passive_list: + case XENOPROF_reserve_counters: + case XENOPROF_setup_events: + case XENOPROF_enable_virq: + case XENOPROF_start: + case XENOPROF_stop: + case XENOPROF_disable_virq: + case XENOPROF_release_counters: + case XENOPROF_shutdown: + return xencomm_arch_hypercall_xenoprof_op(op, arg); + break; + + default: + printk("%s: op %d isn't supported\n", __func__, op); + return -ENOSYS; + } + return xencomm_arch_hypercall_xenoprof_op(op, + xencomm_create_inline(arg)); +} +#endif + +#ifdef CONFIG_PERFMON +int +xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count) +{ + switch (cmd) { + case PFM_GET_FEATURES: + case PFM_CREATE_CONTEXT: + case PFM_WRITE_PMCS: + case PFM_WRITE_PMDS: + case PFM_LOAD_CONTEXT: + break; + + case PFM_DESTROY_CONTEXT: + case PFM_UNLOAD_CONTEXT: + case PFM_START: + case PFM_STOP: + return xencomm_arch_hypercall_perfmon_op(cmd, arg, count); + + default: + printk("%s:%d cmd %ld isn't supported\n", + __func__,__LINE__, cmd); + BUG(); + } + + return xencomm_arch_hypercall_perfmon_op(cmd, + xencomm_create_inline(arg), + count); +} +#endif diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c index 0453cb4437..adc01f1fd5 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c @@ -28,12 +28,14 @@ #include #include #include +#include #ifdef CONFIG_VMX_GUEST #include #else #include #endif #include +#include int xencomm_mini_hypercall_event_channel_op(int cmd, void *op) @@ -320,3 +322,100 @@ xencomm_mini_hypercall_xen_version(int cmd, void *arg) return xencomm_arch_hypercall_xen_version(cmd, desc); } EXPORT_SYMBOL(xencomm_mini_hypercall_xen_version); + +#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) +int +xencomm_mini_hypercall_xenoprof_op(int op, void *arg) +{ + unsigned int argsize; + struct xencomm_mini xc_area[2]; + int nbr_area = 2; + struct xencomm_handle *desc; + int rc; + + switch (op) { + case XENOPROF_init: + argsize = sizeof(xenoprof_init_t); + break; + case XENOPROF_set_active: + argsize = sizeof(domid_t); + break; + case XENOPROF_set_passive: + argsize = sizeof(xenoprof_passive_t); + break; + case XENOPROF_counter: + argsize = sizeof(xenoprof_counter_t); + break; + case XENOPROF_get_buffer: + argsize = sizeof(xenoprof_get_buffer_t); + break; + + case XENOPROF_reset_active_list: + case XENOPROF_reset_passive_list: + case XENOPROF_reserve_counters: + case XENOPROF_setup_events: + case XENOPROF_enable_virq: + case XENOPROF_start: + case XENOPROF_stop: + case XENOPROF_disable_virq: + case XENOPROF_release_counters: + case XENOPROF_shutdown: + return xencomm_arch_hypercall_xenoprof_op(op, arg); + + default: + printk("%s: op %d isn't supported\n", __func__, op); + return -ENOSYS; + } + rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); + if (rc) + return rc; + return xencomm_arch_hypercall_xenoprof_op(op, desc); +} +EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_xenoprof_op); +#endif + +#ifdef CONFIG_PERFMON +int +xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, + unsigned long count) +{ + unsigned int argsize; + struct xencomm_mini xc_area[2]; + int nbr_area = 2; + struct xencomm_handle *desc; + int rc; + + switch (cmd) { + case PFM_GET_FEATURES: + argsize = sizeof(pfarg_features_t); + break; + case PFM_CREATE_CONTEXT: + argsize = sizeof(pfarg_context_t); + break; + case PFM_LOAD_CONTEXT: + argsize = sizeof(pfarg_load_t); + break; + case PFM_WRITE_PMCS: + case PFM_WRITE_PMDS: + argsize = sizeof(pfarg_reg_t) * count; + break; + + case PFM_DESTROY_CONTEXT: + case PFM_UNLOAD_CONTEXT: + case PFM_START: + case PFM_STOP: + return xencomm_arch_hypercall_perfmon_op(cmd, arg, count); + + default: + printk("%s:%d cmd %ld isn't supported\n", + __func__, __LINE__, cmd); + BUG(); + } + + rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); + if (rc) + return rc; + return xencomm_arch_hypercall_perfmon_op(cmd, desc, count); +} +EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_perfmon_op); +#endif diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h index 7a522be483..67b8526f69 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h @@ -271,6 +271,12 @@ HYPERVISOR_physdev_op(int cmd, void *arg) } } +static inline int +xencomm_arch_hypercall_xenoprof_op(int op, struct xencomm_handle *arg) +{ + return _hypercall2(int, xenoprof_op, op, arg); +} + extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); static inline void exit_idle(void) {} #define do_IRQ(irq, regs) ({ \ @@ -393,6 +399,17 @@ HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, } #endif +#ifdef CONFIG_PERFMON +static inline int +xencomm_arch_hypercall_perfmon_op(unsigned long cmd, + struct xencomm_handle *arg, + unsigned long count) +{ + return _hypercall4(int, ia64_dom0vp_op, + IA64_DOM0VP_perfmon, cmd, arg, count); +} +#endif + // for balloon driver #define HYPERVISOR_update_va_mapping(va, new_val, flags) (0) @@ -406,6 +423,8 @@ HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, #define HYPERVISOR_console_io xencomm_mini_hypercall_console_io #define HYPERVISOR_hvm_op xencomm_mini_hypercall_hvm_op #define HYPERVISOR_memory_op xencomm_mini_hypercall_memory_op +#define HYPERVISOR_xenoprof_op xencomm_mini_hypercall_xenoprof_op +#define HYPERVISOR_perfmon_op xencomm_mini_hypercall_perfmon_op #else #define HYPERVISOR_sched_op xencomm_hypercall_sched_op #define HYPERVISOR_event_channel_op xencomm_hypercall_event_channel_op @@ -415,6 +434,8 @@ HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, #define HYPERVISOR_console_io xencomm_hypercall_console_io #define HYPERVISOR_hvm_op xencomm_hypercall_hvm_op #define HYPERVISOR_memory_op xencomm_hypercall_memory_op +#define HYPERVISOR_xenoprof_op xencomm_hypercall_xenoprof_op +#define HYPERVISOR_perfmon_op xencomm_hypercall_perfmon_op #endif #define HYPERVISOR_suspend xencomm_hypercall_suspend diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h index 3c073a71cd..df5204f469 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h @@ -46,6 +46,15 @@ extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg); extern int xencomm_hypercall_suspend(unsigned long srec); +#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) +extern int xencomm_hypercall_xenoprof_op(int op, void *arg); +#endif + +#ifdef CONFIG_PERFMON +extern int xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, + unsigned long count); +#endif + /* Using mini xencomm. */ extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str); @@ -68,6 +77,15 @@ extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg); extern unsigned long xencomm_mini_hypercall_hvm_op(int cmd, void *arg); +#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) +extern int xencomm_mini_hypercall_xenoprof_op(int op, void *arg); +#endif + +#ifdef CONFIG_PERFMON +extern int xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, + unsigned long count); +#endif + /* For privcmd. Locally declare argument type to avoid include storm. Type coherency will be checked within privcmd.c */ struct privcmd_hypercall; diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xenoprof.h b/linux-2.6-xen-sparse/include/asm-ia64/xenoprof.h new file mode 100644 index 0000000000..b45c6ca602 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-ia64/xenoprof.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * asm-ia64/xenoprof.h + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __ASM_XENOPROF_H__ +#define __ASM_XENOPROF_H__ +#ifdef CONFIG_XEN + +#undef HAVE_XENOPROF_CREATE_FILES + +struct xenoprof_init; +void xenoprof_arch_init_counter(struct xenoprof_init *init); +void xenoprof_arch_counter(void); +void xenoprof_arch_start(void); +void xenoprof_arch_stop(void); + +struct xenoprof_arch_shared_buffer { + struct resource* res; +}; + +struct xenoprof_shared_buffer; +void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer* sbuf); +struct xenoprof_get_buffer; +int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer* get_buffer, + struct xenoprof_shared_buffer* sbuf); +struct xenoprof_passive; +int xenoprof_arch_set_passive(struct xenoprof_passive* pdomain, + struct xenoprof_shared_buffer* sbuf); + +#endif /* CONFIG_XEN */ +#endif /* __ASM_XENOPROF_H__ */ From 1d892b609b9b8422bad3c98cf1a6d6afafb54c05 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 10:48:06 +0000 Subject: [PATCH 049/282] [XEN] Emulator fixes. 1. Fix RIP-relative EA calculation. Immediate operands are never 64-bit. 2. Displacements are sign-extended so used signed types. Signed-off-by: Keir Fraser --- xen/arch/x86/x86_emulate.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 2ce2dfb440..7fb5875a91 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -615,9 +615,9 @@ x86_emulate_memop( } switch ( modrm_mod ) { - case 0: if ( modrm_rm == 6 ) ea = insn_fetch(uint16_t); break; - case 1: ea += insn_fetch(uint8_t); break; - case 2: ea += insn_fetch(uint16_t); break; + case 0: if ( modrm_rm == 6 ) ea = insn_fetch(int16_t); break; + case 1: ea += insn_fetch(int8_t); break; + case 2: ea += insn_fetch(int16_t); break; } } else @@ -632,7 +632,7 @@ x86_emulate_memop( ea = *(long *)decode_register(sib_index, &_regs, 0); ea <<= (sib >> 6) & 3; if ( (modrm_mod == 0) && ((sib_base & 7) == 5) ) - ea += insn_fetch(uint32_t); + ea += insn_fetch(int32_t); else ea += *(long *)decode_register(sib_base, &_regs, 0); } @@ -646,13 +646,13 @@ x86_emulate_memop( case 0: if ( (modrm_rm & 7) != 5 ) break; - ea = insn_fetch(uint32_t); + ea = insn_fetch(int32_t); if ( mode != X86EMUL_MODE_PROT64 ) break; /* Relative to RIP of next instruction. Argh! */ ea += _regs.eip; if ( (d & SrcMask) == SrcImm ) - ea += (d & ByteOp) ? 1 : op_bytes; + ea += (d & ByteOp) ? 1 : ((op_bytes == 8) ? 4 : op_bytes); else if ( (d & SrcMask) == SrcImmByte ) ea += 1; else if ( ((b == 0xf6) || (b == 0xf7)) && @@ -661,8 +661,8 @@ x86_emulate_memop( ea += (d & ByteOp) ? 1 : ((op_bytes == 8) ? 4 : op_bytes); break; - case 1: ea += insn_fetch(uint8_t); break; - case 2: ea += insn_fetch(uint32_t); break; + case 1: ea += insn_fetch(int8_t); break; + case 2: ea += insn_fetch(int32_t); break; } } From bf9423a1fd62f3a19c11f57e0b10f97fb240ae43 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 10:56:02 +0000 Subject: [PATCH 050/282] Diagnose a failure to open the xend-debug.log, and make the /var/log/xen directory on startup, which was the most common reason to fail. Closes bug #823. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvDaemon.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 864c371552..7bfa466dff 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -6,7 +6,9 @@ ########################################################### import os +import os.path import signal +import stat import sys import threading import time @@ -102,17 +104,32 @@ class Daemon: # Detach from standard file descriptors, and redirect them to # /dev/null or the log as appropriate. + # We open the log file first, so that we can diagnose a failure to do + # so _before_ we close stderr. + try: + parent = os.path.dirname(XEND_DEBUG_LOG) + if not os.path.exists(parent): + os.makedirs(parent, stat.S_IRWXU) + fd = os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT|os.O_APPEND) + except Exception, exn: + print >>sys.stderr, exn + print >>sys.stderr, ("Xend failed to open %s. Exiting!" % + XEND_DEBUG_LOG) + sys.exit(1) + os.close(0) os.close(1) os.close(2) if XEND_DEBUG: os.open('/dev/null', os.O_RDONLY) - os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT|os.O_APPEND) - os.dup(1) + os.dup(fd) + os.dup(fd) else: os.open('/dev/null', os.O_RDWR) os.dup(0) - os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT|os.O_APPEND) + os.dup(fd) + os.close(fd) + print >>sys.stderr, ("Xend started at %s." % time.asctime(time.localtime())) From b83e447099583b625860f081fcd3a5f2287385d3 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 10:57:30 +0000 Subject: [PATCH 051/282] Fix for network routing setup. Enables proxy arp on dom0's externally visible interface. Signed-off-by: H. Andres Lagar-Cavilla --- tools/examples/network-route | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/examples/network-route b/tools/examples/network-route index cb217c068d..de535c3280 100755 --- a/tools/examples/network-route +++ b/tools/examples/network-route @@ -16,4 +16,12 @@ # #============================================================================ +dir=$(dirname "$0") +. "$dir/xen-script-common.sh" + +evalVariables "$@" + +netdev=${netdev:-eth${vifnum}} + echo 1 >/proc/sys/net/ipv4/ip_forward +echo 1 >/proc/sys/net/ipv4/conf/${netdev}/proxy_arp From f2b23d6824f84188c07f531c3b0097bb2ee8f698 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 10:58:35 +0000 Subject: [PATCH 052/282] [DOCS] Update for new Xen boot parameters. Signed-off-by: Keir Fraser --- docs/src/user.tex | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/user.tex b/docs/src/user.tex index 2528861a23..f71231d44c 100644 --- a/docs/src/user.tex +++ b/docs/src/user.tex @@ -3240,6 +3240,11 @@ editing \path{grub.conf}. enabled by the BIOS. \item [ apic=bigsmp,default,es7000,summit ] Specify NUMA platform. This can usually be probed automatically. +\item [ dma\_bits=xxx ] Specify width of DMA + addresses in bits. Default is 30 bits (addresses up to 1GB are DMAable). +\item [ dma\_emergency\_pool=xxx ] Specify lower bound on size of DMA + pool below which ordinary allocations will fail rather than fall + back to allocating from the DMA pool. \end{description} In addition, the following options may be specified on the Xen command From 70d02d276ef87d192c014a2440df32ab61f46c12 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 11:07:51 +0000 Subject: [PATCH 053/282] [HVM][VMX] NX bit implies PAE can be enabled. If IA32 VMX guest finds NX bit is there, it may enable PAE even if PAE bit is returned 0 by CPUID. Signed-off-by: Xiaowei Yang --- xen/arch/x86/hvm/vmx/vmx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 2925c06087..7ccd218f53 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -878,15 +878,19 @@ static void vmx_do_cpuid(struct cpu_user_regs *regs) { eax = ebx = ecx = edx = 0x0; } -#ifdef __i386__ else if ( input == CPUID_LEAF_0x80000001 ) { +#if CONFIG_PAGING_LEVELS >= 3 + if ( !v->domain->arch.hvm_domain.params[HVM_PARAM_PAE_ENABLED] ) +#endif + clear_bit(X86_FEATURE_NX & 31, &edx); +#ifdef __i386__ clear_bit(X86_FEATURE_LAHF_LM & 31, &ecx); clear_bit(X86_FEATURE_LM & 31, &edx); clear_bit(X86_FEATURE_SYSCALL & 31, &edx); - } #endif + } } regs->eax = (unsigned long) eax; From 2dcb3ad6f8bfff30545d02da6af389c9b0f9c7b9 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 11:37:59 +0000 Subject: [PATCH 054/282] [LINUX] console: Add option to use /dev/xvc0, major=204, minor=191. The major/minor has now been allocated to us by lanana.org. This is based on previous patches from: Jeremy Katz Amos Waterland Signed-off-by: Keir Fraser --- .../drivers/xen/console/console.c | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c index ff3e2a411e..b2e9d7c783 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c @@ -64,14 +64,21 @@ * 'xencons=off' [XC_OFF]: Console is disabled. * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'. * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'. + * 'xencons=xvc' [XC_SERIAL]: Console attached to '/dev/xvc0'. * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. * * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses * warnings from standard distro startup scripts. */ -static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT; +static enum { + XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC +} xc_mode = XC_DEFAULT; static int xc_num = -1; +/* /dev/xvc0 device number allocated by lanana.org. */ +#define XEN_XVC_MAJOR 204 +#define XEN_XVC_MINOR 191 + #ifdef CONFIG_MAGIC_SYSRQ static unsigned long sysrq_requested; extern int sysrq_enabled; @@ -82,28 +89,24 @@ static int __init xencons_setup(char *str) char *q; int n; - if (!strncmp(str, "ttyS", 4)) + if (!strncmp(str, "ttyS", 4)) { xc_mode = XC_SERIAL; - else if (!strncmp(str, "tty", 3)) + str += 4; + } else if (!strncmp(str, "tty", 3)) { xc_mode = XC_TTY; - else if (!strncmp(str, "off", 3)) + str += 3; + } else if (!strncmp(str, "xvc", 3)) { + xc_mode = XC_XVC; + str += 3; + } else if (!strncmp(str, "off", 3)) { xc_mode = XC_OFF; - - switch (xc_mode) { - case XC_SERIAL: - n = simple_strtol(str+4, &q, 10); - if (q > (str + 4)) - xc_num = n; - break; - case XC_TTY: - n = simple_strtol(str+3, &q, 10); - if (q > (str + 3)) - xc_num = n; - break; - default: - break; + str += 3; } + n = simple_strtol(str, &q, 10); + if (q != str) + xc_num = n; + return 1; } __setup("xencons=", xencons_setup); @@ -201,6 +204,12 @@ static int __init xen_console_init(void) } switch (xc_mode) { + case XC_XVC: + strcpy(kcons_info.name, "xvc"); + if (xc_num == -1) + xc_num = 0; + break; + case XC_SERIAL: strcpy(kcons_info.name, "ttyS"); if (xc_num == -1) @@ -305,7 +314,7 @@ void dom0_init_screen_info(const struct dom0_vga_console_info *info) /******************** User-space console driver (/dev/console) ************/ #define DRV(_d) (_d) -#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \ +#define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) && \ ((_tty)->index != (xc_num - 1))) static struct termios *xencons_termios[MAX_NR_CONSOLES]; @@ -628,8 +637,8 @@ static int __init xencons_init(void) return rc; } - xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? - 1 : MAX_NR_CONSOLES); + xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ? + MAX_NR_CONSOLES : 1); if (xencons_driver == NULL) return -ENOMEM; @@ -644,14 +653,23 @@ static int __init xencons_init(void) DRV(xencons_driver)->termios = xencons_termios; DRV(xencons_driver)->termios_locked = xencons_termios_locked; - if (xc_mode == XC_SERIAL) { + switch (xc_mode) { + case XC_XVC: + DRV(xencons_driver)->name = "xvc"; + DRV(xencons_driver)->major = XEN_XVC_MAJOR; + DRV(xencons_driver)->minor_start = XEN_XVC_MINOR; + DRV(xencons_driver)->name_base = xc_num; + break; + case XC_SERIAL: DRV(xencons_driver)->name = "ttyS"; DRV(xencons_driver)->minor_start = 64 + xc_num; - DRV(xencons_driver)->name_base = 0 + xc_num; - } else { + DRV(xencons_driver)->name_base = xc_num; + break; + default: DRV(xencons_driver)->name = "tty"; DRV(xencons_driver)->minor_start = 1; DRV(xencons_driver)->name_base = 1; + break; } tty_set_operations(xencons_driver, &xencons_ops); From f46695b45bc70b2b4824d552874514adaff146b5 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 11:38:17 +0000 Subject: [PATCH 055/282] [HVMLOADER] Fix CFLAGS. Signed-off-by: Keir Fraser --- tools/firmware/hvmloader/Makefile | 5 +---- tools/firmware/hvmloader/acpi/Makefile | 7 +++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index 39d8a20fae..829a9dec87 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -28,16 +28,13 @@ include $(XEN_ROOT)/Config.mk # The HVM loader is started in 32-bit mode at the address below: LOADADDR = 0x100000 -DEFINES =-DDEBUG -XENINC =-I$(XEN_ROOT)/tools/libxc - # Disable PIE/SSP if GCC supports them. They can break us. CFLAGS += $(call cc-option,$(CC),-nopie,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) OBJCOPY = objcopy -CFLAGS += $(DEFINES) -I. $(XENINC) -fno-builtin -O2 -msoft-float +CFLAGS += -I$(XEN_ROOT)/tools/libxc -I. -fno-builtin -O2 -msoft-float LDFLAGS = -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR) SRCS = hvmloader.c mp_tables.c util.c smbios.c diff --git a/tools/firmware/hvmloader/acpi/Makefile b/tools/firmware/hvmloader/acpi/Makefile index cd05e21a5e..16803d78d6 100644 --- a/tools/firmware/hvmloader/acpi/Makefile +++ b/tools/firmware/hvmloader/acpi/Makefile @@ -27,6 +27,13 @@ OBJS = $(patsubst %.c,%.o,$(C_SRC)) IASL_VER = acpica-unix-20050513 IASL_URL = http://developer.intel.com/technology/iapc/acpi/downloads/$(IASL_VER).tar.gz +# Disable PIE/SSP if GCC supports them. They can break us. +CFLAGS += $(call cc-option,$(CC),-nopie,) +CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) +CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) + +CFLAGS += -fno-builtin -O2 -msoft-float + vpath iasl $(PATH) all: acpi.a From 5c6e15bd79228e8c9ce56d6985a8a18e8b42f6dc Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 11:40:10 +0000 Subject: [PATCH 056/282] [XENOPROFILE, LINUX] compilation fix on x86_64 Signed-off-by: Isaku Yamahata --- xen/include/public/xenoprof.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xen/include/public/xenoprof.h b/xen/include/public/xenoprof.h index a624b73249..5bd4c0dc38 100644 --- a/xen/include/public/xenoprof.h +++ b/xen/include/public/xenoprof.h @@ -29,6 +29,8 @@ #ifndef __XEN_PUBLIC_XENOPROF_H__ #define __XEN_PUBLIC_XENOPROF_H__ +#include "xen.h" + /* * Commands to HYPERVISOR_xenoprof_op(). */ From 536c3bc7890bae1ea9903685f0e5c4f4296f05f6 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 12:04:49 +0000 Subject: [PATCH 057/282] [LINUX] console: Fix comment. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/console/console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c index b2e9d7c783..cf5b63a997 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c @@ -64,7 +64,7 @@ * 'xencons=off' [XC_OFF]: Console is disabled. * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'. * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'. - * 'xencons=xvc' [XC_SERIAL]: Console attached to '/dev/xvc0'. + * 'xencons=xvc' [XC_XVC]: Console attached to '/dev/xvc0'. * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. * * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses From 26c7d2863579692ba546c064989ecb4ebac44941 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 12:14:45 +0000 Subject: [PATCH 058/282] Silence log message when trying to unregister a watch that's already been unregistered -- this is not a problem. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/xenstore/xswatch.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/xenstore/xswatch.py b/tools/python/xen/xend/xenstore/xswatch.py index e84fe83ba9..a1ea740a94 100644 --- a/tools/python/xen/xend/xenstore/xswatch.py +++ b/tools/python/xen/xend/xenstore/xswatch.py @@ -5,6 +5,7 @@ # Public License. See the file "COPYING" in the main directory of # this archive for more details. +import errno import threading from xen.xend.xenstore.xsutil import xshandle @@ -65,7 +66,15 @@ def watchMain(): watch = we[1] res = watch.fn(we[0], *watch.args, **watch.kwargs) if not res: - watch.unwatch() + try: + watch.unwatch() + except RuntimeError, exn: + if exn.args[0] == errno.ENOENT: + # The watch has already been unregistered -- that's + # fine. + pass + else: + raise except: log.exception("read_watch failed") # Ignore this exception -- there's no point throwing it From dcf51b3413425dc8e382846c858aba21ec157d35 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 12:15:45 +0000 Subject: [PATCH 059/282] Move the assert under the protection of the in_transaction flag. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/xenstore/xstransact.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/xenstore/xstransact.py b/tools/python/xen/xend/xenstore/xstransact.py index c6a3bb9d82..dd9aa98544 100644 --- a/tools/python/xen/xend/xenstore/xstransact.py +++ b/tools/python/xen/xend/xenstore/xstransact.py @@ -11,11 +11,12 @@ from xen.xend.xenstore.xsutil import xshandle class xstransact: def __init__(self, path = ""): - assert path is not None self.in_transaction = False # Set this temporarily -- if this # constructor fails, then we need to # protect __del__. + + assert path is not None self.path = path.rstrip("/") self.transaction = xshandle().transaction_start() self.in_transaction = True From 001bc372b4b553e523d574e6b834774223798384 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 12:16:19 +0000 Subject: [PATCH 060/282] Fix xm new -F -- this fix was recently introduced for xm create. Signed-off-by: Ewan Mellor --- tools/python/xen/xm/new.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/python/xen/xm/new.py b/tools/python/xen/xm/new.py index fec2fc76e6..7af65510a9 100644 --- a/tools/python/xen/xm/new.py +++ b/tools/python/xen/xm/new.py @@ -58,6 +58,12 @@ def main(argv): if not opts: return + if type(config) == str: + try: + config = sxp.parse(file(config))[0] + except IOError, exn: + raise OptionError("Cannot read file %s: %s" % (config, exn[1])) + if opts.vals.dryrun: PrettyPrint.prettyprint(config) else: From 74517de10474ba9cabca6ed1c68dff94b24000c1 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 12:16:59 +0000 Subject: [PATCH 061/282] [LINUX] Avoid triggering the softlockup BUG when offline for too long. After being offline for a long time, the softlockup watchdog triggers a BUG() on our faces. This is expected, as in fact, we spent more than a fixed 10*HZ amount of time without touching the watchdog. However, by inspecting the contents of stolen inside timer irq handler, we can gain awareness of the fact, and do better than that. Signed-off-by: Glauber de Oliveira Costa --- linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c index 05f3c47e50..93388ea67a 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c @@ -710,6 +710,10 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) (cputime_t)delta_cpu); } + /* Offlined for more than a few seconds? Avoid lockup warnings. */ + if (stolen > 5*HZ) + touch_softlockup_watchdog(); + /* Local timer processing (see update_process_times()). */ run_local_timers(); if (rcu_pending(cpu)) From 72941f1998de71dff2014e4e84284cff57b3dd91 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 29 Nov 2006 12:41:30 +0000 Subject: [PATCH 062/282] [HVMLOADER] Clean up makefile, change TPM detection. Signed-off-by: Keir Fraser --- tools/firmware/hvmloader/Makefile | 8 +++----- tools/firmware/hvmloader/acpi/build.c | 9 ++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tools/firmware/hvmloader/Makefile b/tools/firmware/hvmloader/Makefile index 829a9dec87..763f472987 100644 --- a/tools/firmware/hvmloader/Makefile +++ b/tools/firmware/hvmloader/Makefile @@ -18,12 +18,10 @@ # Place - Suite 330, Boston, MA 02111-1307 USA. # -# External CFLAGS can do more harm than good. -CFLAGS := - override XEN_TARGET_ARCH = x86_32 XEN_ROOT = ../../.. -include $(XEN_ROOT)/Config.mk +CFLAGS := -I$(XEN_ROOT)/tools/libxc -I. +include $(XEN_ROOT)/tools/Rules.mk # The HVM loader is started in 32-bit mode at the address below: LOADADDR = 0x100000 @@ -34,7 +32,7 @@ CFLAGS += $(call cc-option,$(CC),-fno-stack-protector,) CFLAGS += $(call cc-option,$(CC),-fno-stack-protector-all,) OBJCOPY = objcopy -CFLAGS += -I$(XEN_ROOT)/tools/libxc -I. -fno-builtin -O2 -msoft-float +CFLAGS += -fno-builtin -O2 -msoft-float LDFLAGS = -nostdlib -Wl,-N -Wl,-Ttext -Wl,$(LOADADDR) SRCS = hvmloader.c mp_tables.c util.c smbios.c diff --git a/tools/firmware/hvmloader/acpi/build.c b/tools/firmware/hvmloader/acpi/build.c index 241c11332d..b221391807 100644 --- a/tools/firmware/hvmloader/acpi/build.c +++ b/tools/firmware/hvmloader/acpi/build.c @@ -115,7 +115,8 @@ int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs) int offset = 0, nr_tables = 0; struct acpi_20_madt *madt; struct acpi_20_tcpa *tcpa; - static const uint16_t tis_did_vid_rid[] = {0x0001, 0x0001, 0x0001}; + static const uint16_t tis_signature[] = {0x0001, 0x0001, 0x0001}; + uint16_t *tis_hdr; /* MADT. */ if ( (get_vcpu_nr() > 1) || get_apic_mode() ) @@ -126,8 +127,10 @@ int construct_secondary_tables(uint8_t *buf, unsigned long *table_ptrs) } /* TPM TCPA and SSDT. */ - if ( memcmp((char *)0xFED40F00, tis_did_vid_rid, - sizeof(tis_did_vid_rid)) == 0 ) /* Probe for TIS interface. */ + tis_hdr = (uint16_t *)0xFED40F00; + if ( (tis_hdr[0] == tis_signature[0]) && + (tis_hdr[1] == tis_signature[1]) && + (tis_hdr[2] == tis_signature[2]) ) { memcpy(&buf[offset], AmlCode_TPM, sizeof(AmlCode_TPM)); table_ptrs[nr_tables++] = (unsigned long)&buf[offset]; From 1691a97d3bb6cea91f4546a2192d3eb9ae4e949b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 29 Nov 2006 09:16:46 -0700 Subject: [PATCH 063/282] [IA64] remove undefined debugging line Signed-off-by: Alex Williamson --- linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c | 1 - 1 file changed, 1 deletion(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c b/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c index 35e08b5383..2d5a61865d 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/perfmon.c @@ -4151,7 +4151,6 @@ pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) int state, is_system; if (is_running_on_xen()) { - XENPERFMON_PRINTD("PFM_START\n"); if (is_xenoprof_primary()) return HYPERVISOR_perfmon_op(PFM_START, NULL, 0); return 0; From 2f988e7275a8b01ddd869ae88e6db918ea55c9d1 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Wed, 29 Nov 2006 11:05:02 -0700 Subject: [PATCH 064/282] [IA64] Create viosapic handling for IPF. There are three reasons to do this. 1. IOSAPIC is different with IOAPIC such as: 1. IOAPIC implement broadcast, but IOSAPIC doesn't 2. IOSAPIC doesn't implement dest_mode and remote irr bits. 3. IOSAPIC implement EOI but IOAPIC doesn't etc. 2. In IA32 side there are I8259 and LAPIC who are related to IOAPIC, but In IPF there is no I8259 and has LSAPIC. 3. after creating this file, all header files under asm-ia64/hvm, which are linked from IA32 side, are not needed. Signed-off-by: Anthony Xu --- xen/arch/ia64/Makefile | 16 -- xen/arch/ia64/Rules.mk | 2 +- xen/arch/ia64/vmx/Makefile | 2 +- xen/arch/ia64/vmx/mmio.c | 8 +- xen/arch/ia64/vmx/viosapic.c | 354 ++++++++++++++++++++++++++++ xen/arch/ia64/vmx/vlsapic.c | 45 +--- xen/arch/ia64/vmx/vmx_hypercall.c | 3 +- xen/arch/ia64/vmx/vmx_init.c | 8 +- xen/include/asm-ia64/config.h | 5 - xen/include/asm-ia64/domain.h | 2 - xen/include/asm-ia64/viosapic.h | 96 ++++++++ xen/include/asm-ia64/vlsapic.h | 35 ++- xen/include/asm-ia64/vmx.h | 1 - xen/include/asm-ia64/vmx_platform.h | 47 +--- xen/include/asm-ia64/vmx_vpd.h | 11 - 15 files changed, 505 insertions(+), 130 deletions(-) create mode 100644 xen/arch/ia64/vmx/viosapic.c create mode 100644 xen/include/asm-ia64/viosapic.h diff --git a/xen/arch/ia64/Makefile b/xen/arch/ia64/Makefile index 7d297f0c22..fecb8562ee 100644 --- a/xen/arch/ia64/Makefile +++ b/xen/arch/ia64/Makefile @@ -58,17 +58,6 @@ $(BASEDIR)/include/asm-ia64/.offsets.h.stamp: || ln -sf $(BASEDIR)/include/xen $(BASEDIR)/include/linux [ -e $(BASEDIR)/include/asm-ia64/xen ] \ || ln -sf $(BASEDIR)/include/asm-ia64/linux $(BASEDIR)/include/asm-ia64/xen -# Link to HVM files in Xen for ia64/vti - [ -e $(BASEDIR)/include/asm-ia64/hvm/support.h ] \ - || ln -sf ../../../include/asm-x86/hvm/support.h $(BASEDIR)/include/asm-ia64/hvm/support.h - [ -e $(BASEDIR)/include/asm-ia64/hvm/io.h ] \ - || ln -sf ../../../include/asm-x86/hvm/io.h $(BASEDIR)/include/asm-ia64/hvm/io.h - [ -e $(BASEDIR)/include/asm-ia64/hvm/vpic.h ] \ - || ln -sf ../../../include/asm-x86/hvm/vpic.h $(BASEDIR)/include/asm-ia64/hvm/vpic.h - [ -e $(BASEDIR)/include/asm-ia64/hvm/vioapic.h ] \ - || ln -sf ../../../include/asm-x86/hvm/vioapic.h $(BASEDIR)/include/asm-ia64/hvm/vioapic.h - [ -e $(BASEDIR)/arch/ia64/vmx/hvm_vioapic.c ] \ - || ln -sf ../../../arch/x86/hvm/vioapic.c $(BASEDIR)/arch/ia64/vmx/hvm_vioapic.c # I'm sure a Makefile wizard would know a better way to do this xen.lds.s: xen/xen.lds.S @@ -80,8 +69,3 @@ clean:: rm -f *.o *~ core xen.lds.s $(BASEDIR)/include/asm-ia64/.offsets.h.stamp asm-offsets.s map.out rm -f asm-xsi-offsets.s $(BASEDIR)/include/asm-ia64/asm-xsi-offsets.h rm -f $(BASEDIR)/System.map - rm -f vmx/hvm_*.c - rm -f $(BASEDIR)/include/asm-ia64/hvm/support.h - rm -f $(BASEDIR)/include/asm-ia64/hvm/io.h - rm -f $(BASEDIR)/include/asm-ia64/hvm/vpic.h - rm -f $(BASEDIR)/include/asm-ia64/hvm/vioapic.h diff --git a/xen/arch/ia64/Rules.mk b/xen/arch/ia64/Rules.mk index 82f5953aaf..e63faf67ef 100644 --- a/xen/arch/ia64/Rules.mk +++ b/xen/arch/ia64/Rules.mk @@ -33,7 +33,7 @@ CPPFLAGS+= -I$(BASEDIR)/include \ -I$(BASEDIR)/arch/ia64/linux -I$(BASEDIR)/arch/ia64/linux-xen CFLAGS += $(CPPFLAGS) #CFLAGS += -Wno-pointer-arith -Wredundant-decls -CFLAGS += -DIA64 -DXEN -DLINUX_2_6 -DV_IOSAPIC_READY +CFLAGS += -DIA64 -DXEN -DLINUX_2_6 CFLAGS += -ffixed-r13 -mfixed-range=f2-f5,f12-f127 CFLAGS += -g #CFLAGS += -DVTI_DEBUG diff --git a/xen/arch/ia64/vmx/Makefile b/xen/arch/ia64/vmx/Makefile index 5be2b4321c..9b84f6b6b0 100644 --- a/xen/arch/ia64/vmx/Makefile +++ b/xen/arch/ia64/vmx/Makefile @@ -1,4 +1,4 @@ -obj-y += hvm_vioapic.o +obj-y += viosapic.o #obj-y += mm.o obj-y += mmio.o obj-y += pal_emul.o diff --git a/xen/arch/ia64/vmx/mmio.c b/xen/arch/ia64/vmx/mmio.c index 1d6347ef9e..7f3744ba6b 100644 --- a/xen/arch/ia64/vmx/mmio.c +++ b/xen/arch/ia64/vmx/mmio.c @@ -36,6 +36,8 @@ #include #include #include +#include + /* struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) { @@ -271,13 +273,11 @@ static void legacy_io_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) return; } -extern struct vmx_mmio_handler vioapic_mmio_handler; static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int dir) { struct virtual_platform_def *v_plat; //mmio_type_t iot; unsigned long iot; - struct vmx_mmio_handler *vioapic_handler = &vioapic_mmio_handler; iot=__gpfn_is_io(vcpu->domain, src_pa>>PAGE_SHIFT); v_plat = vmx_vcpu_get_plat(vcpu); @@ -293,9 +293,9 @@ static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int break; case GPFN_IOSAPIC: if (!dir) - vioapic_handler->write_handler(vcpu, src_pa, s, *dest); + viosapic_write(vcpu, src_pa, s, *dest); else - *dest = vioapic_handler->read_handler(vcpu, src_pa, s); + *dest = viosapic_read(vcpu, src_pa, s); break; case GPFN_FRAME_BUFFER: case GPFN_LOW_MMIO: diff --git a/xen/arch/ia64/vmx/viosapic.c b/xen/arch/ia64/vmx/viosapic.c new file mode 100644 index 0000000000..8a06ec6046 --- /dev/null +++ b/xen/arch/ia64/vmx/viosapic.c @@ -0,0 +1,354 @@ +/* + * Copyright (C) 2001 MandrakeSoft S.A. + * + * MandrakeSoft S.A. + * 43, rue d'Aboukir + * 75002 Paris - France + * http://www.linux-mandrake.com/ + * http://www.mandrakesoft.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Yunhong Jiang + * Ported to xen by using virtual IRQ line. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void viosapic_deliver(struct viosapic *viosapic, int irq) +{ + uint16_t dest = viosapic->redirtbl[irq].dest_id; + uint8_t delivery_mode = viosapic->redirtbl[irq].delivery_mode; + uint8_t vector = viosapic->redirtbl[irq].vector; + struct vcpu *v; + + switch ( delivery_mode ) + { + // don't support interrupt direct currently + case SAPIC_FIXED: + case SAPIC_LOWEST_PRIORITY: + { + v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest); + vlsapic_set_irq(v, vector); + vcpu_kick(v); + break; + } + case SAPIC_PMI: + case SAPIC_NMI: + case SAPIC_INIT: + case SAPIC_EXTINT: + default: + gdprintk(XENLOG_WARNING, "Unsupported delivery mode %d\n", + delivery_mode); + break; + } +} + + +static int iosapic_get_highest_irq(struct viosapic *viosapic) +{ + uint32_t irqs = viosapic->irr | viosapic->irr_xen; + irqs &= ~viosapic->isr & ~viosapic->imr; + return fls(irqs) - 1; +} + + +/* XXX If level interrupt, use vector->irq table for performance */ +static int get_redir_num(struct viosapic *viosapic, int vector) +{ + int i; + + for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ ) + if ( viosapic->redirtbl[i].vector == vector ) + return i; + + return -1; +} + + +static void service_iosapic(struct viosapic *viosapic) +{ + int irq; + + while ( (irq = iosapic_get_highest_irq(viosapic)) != -1 ) + { + if ( !test_bit(irq, &viosapic->imr) ) + viosapic_deliver(viosapic, irq); + + if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL ) + viosapic->isr |= (1 << irq); + + viosapic->irr &= ~(1 << irq); + viosapic->irr_xen &= ~(1 << irq); + } +} + + +static void viosapic_update_EOI(struct viosapic *viosapic, int vector) +{ + int redir_num; + + if ( (redir_num = get_redir_num(viosapic, vector)) == -1 ) + { + gdprintk(XENLOG_WARNING, "Can't find redir item for %d EOI\n", vector); + return; + } + + if ( !test_and_clear_bit(redir_num, &viosapic->isr) ) + { + gdprintk(XENLOG_WARNING, "redir %d not set for %d EOI\n", + redir_num, vector); + return; + } + service_iosapic(viosapic); +} + + +static unsigned long viosapic_read_indirect(struct viosapic *viosapic, + unsigned long addr, + unsigned long length) +{ + unsigned long result = 0; + + switch ( viosapic->ioregsel ) + { + case VIOSAPIC_VERSION: + result = ((((VIOSAPIC_NUM_PINS - 1) & 0xff) << 16) + | (VIOSAPIC_VERSION_ID & 0xff)); + break; + + default: + { + uint32_t redir_index = (viosapic->ioregsel - 0x10) >> 1; + uint64_t redir_content; + + if ( redir_index >= VIOSAPIC_NUM_PINS ) + { + gdprintk(XENLOG_WARNING, "viosapic_read_indirect:undefined " + "ioregsel %x\n", viosapic->ioregsel); + break; + } + + redir_content = viosapic->redirtbl[redir_index].bits; + result = (viosapic->ioregsel & 0x1) ? + (redir_content >> 32) & 0xffffffff : + redir_content & 0xffffffff; + break; + } + } + + return result; +} + + +unsigned long viosapic_read(struct vcpu *v, + unsigned long addr, + unsigned long length) +{ + struct viosapic *viosapic = vcpu_viosapic(v); + uint32_t result; + + addr &= 0xff; + + switch ( addr ) + { + case VIOSAPIC_REG_SELECT: + result = viosapic->ioregsel; + break; + + case VIOSAPIC_WINDOW: + result = viosapic_read_indirect(viosapic, addr, length); + break; + + default: + result = 0; + break; + } + + return result; +} + + +static inline void viosapic_update_imr(struct viosapic *viosapic, int index) +{ + if ( viosapic->redirtbl[index].mask ) + set_bit(index, &viosapic->imr); + else + clear_bit(index, &viosapic->imr); +} + + +static void viosapic_write_indirect(struct viosapic *viosapic, + unsigned long addr, + unsigned long length, + unsigned long val) +{ + switch ( viosapic->ioregsel ) + { + case VIOSAPIC_VERSION: + /* Writes are ignored. */ + break; + + default: + { + uint32_t redir_index = (viosapic->ioregsel - 0x10) >> 1; + uint64_t redir_content; + + if ( redir_index >= VIOSAPIC_NUM_PINS ) + { + gdprintk(XENLOG_WARNING, "viosapic_write_indirect " + "error register %x\n", viosapic->ioregsel); + break; + } + + redir_content = viosapic->redirtbl[redir_index].bits; + + if ( viosapic->ioregsel & 0x1 ) + { + redir_content = (((uint64_t)val & 0xffffffff) << 32) | + (redir_content & 0xffffffff); + } + else + { + redir_content = ((redir_content >> 32) << 32) | + (val & 0xffffffff); + } + viosapic->redirtbl[redir_index].bits = redir_content; + viosapic_update_imr(viosapic, redir_index); + break; + } + } /* switch */ +} + + +void viosapic_write(struct vcpu *v, + unsigned long addr, + unsigned long length, + unsigned long val) +{ + struct viosapic *viosapic = vcpu_viosapic(v); + + addr &= 0xff; + + switch ( addr ) + { + case VIOSAPIC_REG_SELECT: + viosapic->ioregsel = val; + break; + + case VIOSAPIC_WINDOW: + viosapic_write_indirect(viosapic, addr, length, val); + break; + + case VIOSAPIC_EOI: + viosapic_update_EOI(viosapic, val); + break; + + default: + break; + } +} + + +static void viosapic_reset(struct viosapic *viosapic) +{ + int i; + + memset(viosapic, 0, sizeof(*viosapic)); + + for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ ) + { + viosapic->redirtbl[i].mask = 0x1; + viosapic_update_imr(viosapic, i); + } + spin_lock_init(&viosapic->lock); +} + + +// this is used by VBD/VNIF to inject interrupt for VTI-domain +void viosapic_set_xen_irq(struct domain *d, int irq, int level) +{ + struct viosapic *viosapic = domain_viosapic(d); + + spin_lock(&viosapic->lock); + if ( viosapic->redirtbl[irq].mask ) + goto out; + + if ( viosapic->redirtbl[irq].trig_mode == SAPIC_EDGE) + gdprintk(XENLOG_WARNING, "Forcing edge triggered APIC irq %d?\n", irq); + + if ( level ) + viosapic->irr_xen |= 1 << irq; + else + viosapic->irr_xen &= ~(1 << irq); + + service_iosapic(viosapic); +out: + spin_unlock(&viosapic->lock); +} + + +void viosapic_set_irq(struct domain *d, int irq, int level) +{ + struct viosapic *viosapic = domain_viosapic(d); + uint32_t bit; + + spin_lock(&viosapic->lock); + if ( (irq < 0) || (irq >= VIOSAPIC_NUM_PINS) ) + goto out; + + if ( viosapic->redirtbl[irq].mask ) + goto out; + + bit = 1 << irq; + if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL ) + { + if ( level ) + viosapic->irr |= bit; + else + viosapic->irr &= ~bit; + } + else + { + if ( level ) + /* XXX No irr clear for edge interrupt */ + viosapic->irr |= bit; + } + + service_iosapic(viosapic); +out: + spin_unlock(&viosapic->lock); +} + + +void viosapic_init(struct domain *d) +{ + struct viosapic *viosapic = domain_viosapic(d); + + viosapic_reset(viosapic); + + viosapic->base_address = VIOSAPIC_DEFAULT_BASE_ADDRESS; +} diff --git a/xen/arch/ia64/vmx/vlsapic.c b/xen/arch/ia64/vmx/vlsapic.c index 5e4ccbd8fd..d2963fdf91 100644 --- a/xen/arch/ia64/vmx/vlsapic.c +++ b/xen/arch/ia64/vmx/vlsapic.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include //u64 fire_itc; @@ -330,29 +330,6 @@ void vtm_domain_in(VCPU *vcpu) } */ -#ifdef V_IOSAPIC_READY -int vlapic_match_logical_addr(struct vlapic *vlapic, uint16_t dest) -{ - return (VLAPIC_ID(vlapic) == dest); -} - -struct vlapic* apic_round_robin(struct domain *d, - uint8_t vector, - uint32_t bitmap) -{ - uint8_t bit = 0; - - if (!bitmap) { - printk(" no bit on bitmap\n"); - return NULL; - } - - while (!(bitmap & (1 << bit))) - bit++; - - return vcpu_vlapic(d->vcpu[bit]); -} -#endif void vlsapic_reset(VCPU *vcpu) { @@ -375,9 +352,6 @@ void vlsapic_reset(VCPU *vcpu) VLSAPIC_INSVC(vcpu,i) = 0; } -#ifdef V_IOSAPIC_READY - vcpu->arch.arch_vmx.vlapic.vcpu = vcpu; -#endif dprintk(XENLOG_INFO, "VLSAPIC inservice base=%p\n", &VLSAPIC_INSVC(vcpu,0) ); } @@ -667,13 +641,12 @@ void vmx_vexirq(VCPU *vcpu) generate_exirq (vcpu); } - -void vmx_vioapic_set_irq(struct domain *d, int irq, int level) +struct vcpu * vlsapic_lid_to_vcpu(struct domain *d, uint16_t dest) { - unsigned long flags; - - spin_lock_irqsave(&d->arch.arch_vmx.virq_assist_lock, flags); - vioapic_set_irq(d, irq, level); - spin_unlock_irqrestore(&d->arch.arch_vmx.virq_assist_lock, flags); -} - + struct vcpu * v; + for_each_vcpu ( d, v ) { + if ( (v->arch.privregs->lid >> 16) == dest ) + return v; + } + return NULL; +} diff --git a/xen/arch/ia64/vmx/vmx_hypercall.c b/xen/arch/ia64/vmx/vmx_hypercall.c index dcb571e042..e9acb6ec5d 100644 --- a/xen/arch/ia64/vmx/vmx_hypercall.c +++ b/xen/arch/ia64/vmx/vmx_hypercall.c @@ -35,6 +35,7 @@ #include #include #include +#include long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) @@ -96,7 +97,7 @@ do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) rc = -EINVAL; if (is_hvm_domain(d)) { - vmx_vioapic_set_irq(d, op.irq, op.level); + viosapic_set_irq(d, op.irq, op.level); rc = 0; } diff --git a/xen/arch/ia64/vmx/vmx_init.c b/xen/arch/ia64/vmx/vmx_init.c index ea6025eecc..c4cb0150ea 100644 --- a/xen/arch/ia64/vmx/vmx_init.c +++ b/xen/arch/ia64/vmx/vmx_init.c @@ -48,13 +48,12 @@ #include #include #include -#include +#include #include #include /* Global flag to identify whether Intel vmx feature is on */ u32 vmx_enabled = 0; -unsigned int opt_vmx_debug_level = 0; static u32 vm_order; static u64 buffer_size; static u64 vp_env_info; @@ -396,11 +395,8 @@ void vmx_setup_platform(struct domain *d) memset(&d->shared_info->evtchn_mask[0], 0xff, sizeof(d->shared_info->evtchn_mask)); - /* initiate spinlock for pass virq */ - spin_lock_init(&d->arch.arch_vmx.virq_assist_lock); - /* Initialize iosapic model within hypervisor */ - vioapic_init(d); + viosapic_init(d); } void vmx_do_launch(struct vcpu *v) diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index bb71eb8c12..0e628e1714 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -283,9 +283,4 @@ struct screen_info { }; /* Define CONFIG_PRIVIFY to support privified OS (deprecated). */ #undef CONFIG_PRIVIFY -/* Necessary for hvm_vioapic.c */ -#define vcpu_vlapic(vcpu) (&(vcpu)->arch.arch_vmx.vlapic) -#define vlapic_vcpu(vpic) (container_of((vpic), struct vcpu, \ - arch.arch_vmx.vlapic)) - #endif /* _IA64_CONFIG_H_ */ diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 251ffda02a..1e9d8af21b 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -124,8 +124,6 @@ struct arch_domain { struct last_vcpu last_vcpu[NR_CPUS]; - struct arch_vmx_domain arch_vmx; /* Virtual Machine Extensions */ - #ifdef CONFIG_XEN_IA64_TLB_TRACK struct tlb_track* tlb_track; #endif diff --git a/xen/include/asm-ia64/viosapic.h b/xen/include/asm-ia64/viosapic.h new file mode 100644 index 0000000000..42b54e822c --- /dev/null +++ b/xen/include/asm-ia64/viosapic.h @@ -0,0 +1,96 @@ +/* + * + * Copyright (C) 2001 MandrakeSoft S.A. + * + * MandrakeSoft S.A. + * 43, rue d'Aboukir + * 75002 Paris - France + * http://www.linux-mandrake.com/ + * http://www.mandrakesoft.com/ + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ASM_IA64_VMX_VIOSAPIC_H__ +#define __ASM_IA64_VMX_VIOSAPIC_H__ + +#include +#include +#include + +/* Direct registers. */ +#define VIOSAPIC_REG_SELECT 0x00 +#define VIOSAPIC_WINDOW 0x10 +#define VIOSAPIC_EOI 0x40 + +#define VIOSAPIC_VERSION 0x1 + +#define VIOSAPIC_DEST_SHIFT 16 + + +#define VIOSAPIC_VERSION_ID 0x21 /* IOSAPIC version */ + +#define VIOSAPIC_NUM_PINS 24 + +#define VIOSAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 +#define VIOSAPIC_MEM_LENGTH 0x100 + +#define domain_viosapic(d) (&(d)->arch.hvm_domain.viosapic) +#define viosapic_domain(v) (container_of((v), struct domain, \ + arch.hvm_domain.viosapic)) +#define vcpu_viosapic(v) (&(v)->domain->arch.hvm_domain.viosapic) + +union viosapic_rte +{ + uint64_t bits; + struct { + uint8_t vector; + + uint8_t delivery_mode : 3; + uint8_t reserve1 : 1; + uint8_t delivery_status: 1; + uint8_t polarity : 1; + uint8_t reserve2 : 1; + uint8_t trig_mode : 1; + + uint8_t mask : 1; + uint8_t reserve3 : 7; + + uint8_t reserved[3]; + uint16_t dest_id; + }; +}; + +struct viosapic { + uint32_t irr; + uint32_t irr_xen; /* interrupts forced on by the hypervisor. */ + uint32_t isr; /* This is used for level trigger */ + uint32_t imr; + uint32_t ioregsel; + spinlock_t lock; + unsigned long base_address; + union viosapic_rte redirtbl[VIOSAPIC_NUM_PINS]; +}; + +void viosapic_init(struct domain *d); +void viosapic_set_xen_irq(struct domain *d, int irq, int level); +void viosapic_set_irq(struct domain *d, int irq, int level); +void viosapic_write(struct vcpu *v, unsigned long addr, + unsigned long length, unsigned long val); + +unsigned long viosapic_read(struct vcpu *v, unsigned long addr, + unsigned long length); + +#endif /* __ASM_IA64_VMX_VIOSAPIC_H__ */ diff --git a/xen/include/asm-ia64/vlsapic.h b/xen/include/asm-ia64/vlsapic.h index 98bc88f9df..8cfc1db64a 100644 --- a/xen/include/asm-ia64/vlsapic.h +++ b/xen/include/asm-ia64/vlsapic.h @@ -23,6 +23,37 @@ #ifndef _LSAPIC_H #define _LSAPIC_H #include +#include +/* + *Delivery mode + */ +#define SAPIC_DELIV_SHIFT 8 +#define SAPIC_FIXED 0x0 +#define SAPIC_LOWEST_PRIORITY 0x1 +#define SAPIC_PMI 0x2 +#define SAPIC_NMI 0x4 +#define SAPIC_INIT 0x5 +#define SAPIC_EXTINT 0x7 + +/* + *Interrupt polarity + */ +#define SAPIC_POLARITY_SHIFT 13 +#define SAPIC_POL_HIGH 0 +#define SAPIC_POL_LOW 1 + +/* + *Trigger mode + */ +#define SAPIC_TRIGGER_SHIFT 15 +#define SAPIC_EDGE 0 +#define SAPIC_LEVEL 1 + +/* + *Mask bit + */ +#define SAPIC_MASK_SHIFT 16 +#define SAPIC_MASK (1 << SAPIC_MASK_SHIFT) extern void vtm_init(struct vcpu *vcpu); extern void vtm_set_itc(struct vcpu *vcpu, uint64_t new_itc); @@ -30,5 +61,7 @@ extern void vtm_set_itm(struct vcpu *vcpu, uint64_t val); extern void vtm_set_itv(struct vcpu *vcpu, uint64_t val); extern void vmx_vexirq(struct vcpu *vcpu); extern void vhpi_detection(struct vcpu *vcpu); - +extern int vmx_vcpu_pend_interrupt(VCPU * vcpu, uint8_t vector); +extern struct vcpu * vlsapic_lid_to_vcpu(struct domain *d, uint16_t dest); +#define vlsapic_set_irq vmx_vcpu_pend_interrupt #endif diff --git a/xen/include/asm-ia64/vmx.h b/xen/include/asm-ia64/vmx.h index 344ef44b95..4e0971278a 100644 --- a/xen/include/asm-ia64/vmx.h +++ b/xen/include/asm-ia64/vmx.h @@ -55,7 +55,6 @@ extern void vmx_relinquish_guest_resources(struct domain *d); extern void vmx_relinquish_vcpu_resources(struct vcpu *v); extern void vmx_die_if_kernel(char *str, struct pt_regs *regs, long err); extern void vmx_send_assist_req(struct vcpu *v); -extern void vmx_vioapic_set_irq(struct domain *d, int irq, int level); static inline vcpu_iodata_t *get_vio(struct domain *d, unsigned long cpu) { diff --git a/xen/include/asm-ia64/vmx_platform.h b/xen/include/asm-ia64/vmx_platform.h index 7239fd1793..131e3f90f8 100644 --- a/xen/include/asm-ia64/vmx_platform.h +++ b/xen/include/asm-ia64/vmx_platform.h @@ -21,7 +21,7 @@ #include #include -#include +#include struct mmio_list; typedef struct virtual_platform_def { unsigned long buffered_io_va; @@ -32,7 +32,7 @@ typedef struct virtual_platform_def { unsigned long params[HVM_NR_PARAMS]; struct mmio_list *mmio; /* One IOSAPIC now... */ - struct vioapic vioapic; + struct viosapic viosapic; } vir_plat_t; static inline int __fls(uint32_t word) @@ -43,47 +43,4 @@ static inline int __fls(uint32_t word) __asm__ __volatile__ ("getf.exp %0=%1" : "=r"(exp) : "f"(d)); return word ? (exp - 0xffff) : -1; } - -/* This is a connect structure between vIOSAPIC model and vLSAPIC model. - * vlapic is required by vIOSAPIC model to manipulate pending bits, and - * we just map them into vpd here - */ -typedef struct vlapic { - struct vcpu *vcpu; /* Link to current vcpu */ -} vlapic_t; - -extern uint64_t dummy_tmr[]; -#define VLAPIC_ID(l) (uint16_t)(((l)->vcpu->arch.privregs->lid) >> 16) -#define VLAPIC_IRR(l) ((l)->vcpu->arch.privregs->irr[0]) -struct vlapic *apic_round_robin(struct domain *d, uint8_t vector, uint32_t bitmap); -extern int vmx_vcpu_pend_interrupt(struct vcpu *vcpu, uint8_t vector); -static inline int vlapic_set_irq(struct vlapic *t, uint8_t vec, uint8_t trig) -{ - return vmx_vcpu_pend_interrupt(t->vcpu, vec); -} - -enum ioapic_irq_destination_types { - dest_Fixed = 0, - dest_LowestPrio = 1, - dest_SMI = 2, - dest__reserved_1 = 3, - dest_NMI = 4, - dest_INIT = 5, - dest__reserved_2 = 6, - dest_ExtINT = 7 -}; - -#define vlapic_enabled(l) 1 - -#define VLAPIC_DELIV_MODE_FIXED 0x0 -#define VLAPIC_DELIV_MODE_REDIR 0x1 -#define VLAPIC_DELIV_MODE_LPRI VLAPIC_DELIV_MODE_REDIR -#define VLAPIC_DELIV_MODE_PMI 0x2 -#define VLAPIC_DELIV_MODE_SMI 0x2 /* For IA32 */ -#define VLAPIC_DELIV_MODE_RESERVED 0x3 -#define VLAPIC_DELIV_MODE_NMI 0x4 -#define VLAPIC_DELIV_MODE_INIT 0x5 -#define VLAPIC_DELIV_MODE_STARTUP 0x6 /* For IA32 */ -#define VLAPIC_DELIV_MODE_EXT 0x7 - #endif diff --git a/xen/include/asm-ia64/vmx_vpd.h b/xen/include/asm-ia64/vmx_vpd.h index 17496d25f2..f6676150b2 100644 --- a/xen/include/asm-ia64/vmx_vpd.h +++ b/xen/include/asm-ia64/vmx_vpd.h @@ -74,14 +74,9 @@ struct ivt_debug{ #define IVT_DEBUG_MAX 128 #endif -struct arch_vmx_domain { - spinlock_t virq_assist_lock; /* spinlock for pass virq */ -}; - struct arch_vmx_struct { // vpd_t *vpd; vtime_t vtm; - struct vlapic vlapic; unsigned long vrr[8]; /* if the corresponding bit is 1, then this page size is used in this region */ @@ -118,12 +113,6 @@ struct arch_vmx_struct { #define ARCH_VMX_IO_WAIT 3 /* Waiting for I/O completion */ #define ARCH_VMX_DOMAIN 5 /* Need it to indicate VTi domain */ - -#define VMX_DEBUG 1 -#if VMX_DEBUG - -extern unsigned int opt_vmx_debug_level; -#endif #endif //__ASSEMBLY__ // VPD field offset From ef7c4eec7bed3fb5a99b162aa452ca4b8571c16c Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 23:31:07 +0000 Subject: [PATCH 065/282] New modelling for consoles -- have them as separate classes attached to the VM, much like the arrangements for devices. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 320 ++++++++++++++++++ tools/libxen/include/xen_console.h | 207 +++++++++++ tools/libxen/include/xen_console_decl.h | 30 ++ tools/libxen/include/xen_console_protocol.h | 82 +++++ .../include/xen_console_protocol_internal.h | 37 ++ tools/libxen/include/xen_vm.h | 9 + tools/libxen/src/xen_console.c | 207 +++++++++++ tools/libxen/src/xen_console_protocol.c | 82 +++++ tools/libxen/src/xen_vm.c | 22 ++ 9 files changed, 996 insertions(+) create mode 100644 tools/libxen/include/xen_console.h create mode 100644 tools/libxen/include/xen_console_decl.h create mode 100644 tools/libxen/include/xen_console_protocol.h create mode 100644 tools/libxen/include/xen_console_protocol_internal.h create mode 100644 tools/libxen/src/xen_console.c create mode 100644 tools/libxen/src/xen_console_protocol.c diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 8c06fb8a33..81cd8828d4 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -34,6 +34,7 @@ Name & Description \\ {\tt VDI} & A virtual disk image \\ {\tt VBD} & A virtual block device \\ {\tt VTPM} & A virtual TPM device \\ +{\tt console} & A console \\ {\tt user} & A user of the system \\ {\tt debug} & A basic class for testing \\ \hline @@ -54,6 +55,7 @@ PIF.host & host.PIFs & one-to-many\\ PIF.network & network.PIFs & one-to-many\\ SR.VDIs & VDI.SR & many-to-one\\ VTPM.VM & VM.VTPMs & one-to-many\\ +console.VM & VM.consoles & one-to-many\\ host.resident\_VMs & VM.resident\_on & many-to-one\\ host.host\_CPUs & host\_cpu.host & many-to-one\\ \hline @@ -97,6 +99,16 @@ Map (a $\rightarrow$ b) & a table mapping values of type a to values of type b \ \subsection{Enumeration types} The following enumeration types are used: +\begin{longtable}{|ll|} +\hline +{\tt enum console\_protocol} & \\ +\hline +\hspace{0.5cm}{\tt vt100} & VT100 terminal \\ +\hspace{0.5cm}{\tt rfb} & Remote FrameBuffer protocol (as used in VNC) \\ +\hspace{0.5cm}{\tt rdp} & Remote Desktop Protocol \\ +\hline +\end{longtable} + \begin{longtable}{|ll|} \hline {\tt enum vdi\_type} & \\ @@ -947,6 +959,7 @@ $\mathit{RW}$ & {\tt actions/after\_shutdown} & on\_normal\_exit & action to ta $\mathit{RW}$ & {\tt actions/after\_reboot} & on\_normal\_exit & action to take after the guest has rebooted itself \\ $\mathit{RW}$ & {\tt actions/after\_suspend} & on\_normal\_exit & action to take after the guest has suspended itself \\ $\mathit{RW}$ & {\tt actions/after\_crash} & on\_crash\_behaviour & action to take if the guest crashes \\ +$\mathit{RO}_\mathit{run}$ & {\tt consoles} & (console ref) Set & virtual console devices \\ $\mathit{RO}_\mathit{run}$ & {\tt VIFs} & (VIF ref) Set & virtual network interfaces \\ $\mathit{RO}_\mathit{run}$ & {\tt VBDs} & (VBD ref) Set & virtual block devices \\ $\mathit{RO}_\mathit{run}$ & {\tt VTPMs} & (VTPM ref) Set & virtual TPMs \\ @@ -2628,6 +2641,38 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_consoles} + +{\bf Overview:} +Get the consoles field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} ((console ref) Set) get_consoles (session_id s, VM ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & object instance \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +(console ref) Set +} + + +value of the field \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -9185,6 +9230,281 @@ all fields from the object \vspace{0.3cm} \vspace{0.3cm} +\vspace{1cm} +\newpage +\section{Class: console} +\subsection{Fields for class: console} +\begin{longtable}{|lllp{0.38\textwidth}|} +\hline +\multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf console} \\ +\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A console}} \\ +\hline +Quals & Field & Type & Description \\ +\hline +$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\ +$\mathit{RO}_\mathit{run}$ & {\tt protocol} & console\_protocol & the protocol used by this console \\ +$\mathit{RO}_\mathit{run}$ & {\tt uri} & string & URI for the console service \\ +$\mathit{RO}_\mathit{run}$ & {\tt VM} & VM ref & VM to which this console is attached \\ +\hline +\end{longtable} +\subsection{Additional RPCs associated with class: console} +\subsubsection{RPC name:~get\_record} + +{\bf Overview:} +Get the current state of the given console. + + \noindent {\bf Signature:} +\begin{verbatim} (console record) get_record (session_id s, console ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +console record +} + + +all fields from the object +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_by\_uuid} + +{\bf Overview:} +Get a reference to the object with the specified UUID. + + \noindent {\bf Signature:} +\begin{verbatim} (console ref) get_by_uuid (session_id s, string uuid)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt string } & uuid & UUID of object to return \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +console ref +} + + +reference to the object +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~create} + +{\bf Overview:} +Create a new console instance, and return its handle. + + \noindent {\bf Signature:} +\begin{verbatim} (console ref) create (session_id s, console record args)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console record } & args & All constructor arguments \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +console ref +} + + +reference to the newly created object +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~destroy} + +{\bf Overview:} +Destroy the specified console instance. + + \noindent {\bf Signature:} +\begin{verbatim} void destroy (session_id s, console ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console ref } & self & object instance \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_uuid} + +{\bf Overview:} +Get the uuid field of the given console. + + \noindent {\bf Signature:} +\begin{verbatim} string get_uuid (session_id s, console ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console ref } & self & object instance \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +string +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_protocol} + +{\bf Overview:} +Get the protocol field of the given console. + + \noindent {\bf Signature:} +\begin{verbatim} (console_protocol) get_protocol (session_id s, console ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console ref } & self & object instance \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +console\_protocol +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_uri} + +{\bf Overview:} +Get the uri field of the given console. + + \noindent {\bf Signature:} +\begin{verbatim} string get_uri (session_id s, console ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console ref } & self & object instance \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +string +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_VM} + +{\bf Overview:} +Get the VM field of the given console. + + \noindent {\bf Signature:} +\begin{verbatim} (VM ref) get_VM (session_id s, console ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt console ref } & self & object instance \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +VM ref +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} + \vspace{1cm} \newpage \section{Class: user} diff --git a/tools/libxen/include/xen_console.h b/tools/libxen/include/xen_console.h new file mode 100644 index 0000000000..450c142637 --- /dev/null +++ b/tools/libxen/include/xen_console.h @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2006, XenSource Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef XEN_CONSOLE_H +#define XEN_CONSOLE_H + +#include "xen_common.h" +#include "xen_console_decl.h" +#include "xen_console_protocol.h" +#include "xen_vm_decl.h" + + +/* + * The console class. + * + * A console. + */ + + +/** + * Free the given xen_console. The given handle must have been + * allocated by this library. + */ +extern void +xen_console_free(xen_console console); + + +typedef struct xen_console_set +{ + size_t size; + xen_console *contents[]; +} xen_console_set; + +/** + * Allocate a xen_console_set of the given size. + */ +extern xen_console_set * +xen_console_set_alloc(size_t size); + +/** + * Free the given xen_console_set. The given set must have been + * allocated by this library. + */ +extern void +xen_console_set_free(xen_console_set *set); + + +typedef struct xen_console_record +{ + xen_console handle; + char *uuid; + enum xen_console_protocol protocol; + char *uri; + struct xen_vm_record_opt *vm; +} xen_console_record; + +/** + * Allocate a xen_console_record. + */ +extern xen_console_record * +xen_console_record_alloc(void); + +/** + * Free the given xen_console_record, and all referenced values. The + * given record must have been allocated by this library. + */ +extern void +xen_console_record_free(xen_console_record *record); + + +typedef struct xen_console_record_opt +{ + bool is_record; + union + { + xen_console handle; + xen_console_record *record; + } u; +} xen_console_record_opt; + +/** + * Allocate a xen_console_record_opt. + */ +extern xen_console_record_opt * +xen_console_record_opt_alloc(void); + +/** + * Free the given xen_console_record_opt, and all referenced values. + * The given record_opt must have been allocated by this library. + */ +extern void +xen_console_record_opt_free(xen_console_record_opt *record_opt); + + +typedef struct xen_console_record_set +{ + size_t size; + xen_console_record *contents[]; +} xen_console_record_set; + +/** + * Allocate a xen_console_record_set of the given size. + */ +extern xen_console_record_set * +xen_console_record_set_alloc(size_t size); + +/** + * Free the given xen_console_record_set, and all referenced values. + * The given set must have been allocated by this library. + */ +extern void +xen_console_record_set_free(xen_console_record_set *set); + + + +typedef struct xen_console_record_opt_set +{ + size_t size; + xen_console_record_opt *contents[]; +} xen_console_record_opt_set; + +/** + * Allocate a xen_console_record_opt_set of the given size. + */ +extern xen_console_record_opt_set * +xen_console_record_opt_set_alloc(size_t size); + +/** + * Free the given xen_console_record_opt_set, and all referenced + * values. The given set must have been allocated by this library. + */ +extern void +xen_console_record_opt_set_free(xen_console_record_opt_set *set); + + +/** + * Get the current state of the given console. + */ +extern bool +xen_console_get_record(xen_session *session, xen_console_record **result, xen_console console); + + +/** + * Get a reference to the object with the specified UUID. + */ +extern bool +xen_console_get_by_uuid(xen_session *session, xen_console *result, char *uuid); + + +/** + * Create a new console instance, and return its handle. + */ +extern bool +xen_console_create(xen_session *session, xen_console *result, xen_console_record *record); + + +/** + * Destroy the specified console instance. + */ +extern bool +xen_console_destroy(xen_session *session, xen_console console); + + +/** + * Get the uuid field of the given console. + */ +extern bool +xen_console_get_uuid(xen_session *session, char **result, xen_console console); + + +/** + * Get the protocol field of the given console. + */ +extern bool +xen_console_get_protocol(xen_session *session, enum xen_console_protocol *result, xen_console console); + + +/** + * Get the uri field of the given console. + */ +extern bool +xen_console_get_uri(xen_session *session, char **result, xen_console console); + + +/** + * Get the VM field of the given console. + */ +extern bool +xen_console_get_vm(xen_session *session, xen_vm *result, xen_console console); + + +#endif diff --git a/tools/libxen/include/xen_console_decl.h b/tools/libxen/include/xen_console_decl.h new file mode 100644 index 0000000000..1392164593 --- /dev/null +++ b/tools/libxen/include/xen_console_decl.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2006, XenSource Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef XEN_CONSOLE_DECL_H +#define XEN_CONSOLE_DECL_H + +typedef void *xen_console; + +struct xen_console_set; +struct xen_console_record; +struct xen_console_record_set; +struct xen_console_record_opt; +struct xen_console_record_opt_set; + +#endif diff --git a/tools/libxen/include/xen_console_protocol.h b/tools/libxen/include/xen_console_protocol.h new file mode 100644 index 0000000000..e6fcf62b4a --- /dev/null +++ b/tools/libxen/include/xen_console_protocol.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006, XenSource Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef XEN_CONSOLE_PROTOCOL_H +#define XEN_CONSOLE_PROTOCOL_H + + +#include "xen_common.h" + + +enum xen_console_protocol +{ + /** + * VT100 terminal + */ + XEN_CONSOLE_PROTOCOL_VT100, + + /** + * Remote FrameBuffer protocol (as used in VNC) + */ + XEN_CONSOLE_PROTOCOL_RFB, + + /** + * Remote Desktop Protocol + */ + XEN_CONSOLE_PROTOCOL_RDP +}; + + +typedef struct xen_console_protocol_set +{ + size_t size; + enum xen_console_protocol contents[]; +} xen_console_protocol_set; + +/** + * Allocate a xen_console_protocol_set of the given size. + */ +extern xen_console_protocol_set * +xen_console_protocol_set_alloc(size_t size); + +/** + * Free the given xen_console_protocol_set. The given set must have + * been allocated by this library. + */ +extern void +xen_console_protocol_set_free(xen_console_protocol_set *set); + + +/** + * Return the name corresponding to the given code. This string must + * not be modified or freed. + */ +extern const char * +xen_console_protocol_to_string(enum xen_console_protocol val); + + +/** + * Return the correct code for the given string, or set the session + * object to failure and return an undefined value if the given string does + * not match a known code. + */ +extern enum xen_console_protocol +xen_console_protocol_from_string(xen_session *session, const char *str); + + +#endif diff --git a/tools/libxen/include/xen_console_protocol_internal.h b/tools/libxen/include/xen_console_protocol_internal.h new file mode 100644 index 0000000000..70cdae37af --- /dev/null +++ b/tools/libxen/include/xen_console_protocol_internal.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2006, XenSource Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* + * Declarations of the abstract types used during demarshalling of enum + * xen_console_protocol. Internal to this library -- do not use from outside. + */ + + +#ifndef XEN_CONSOLE_PROTOCOL_INTERNAL_H +#define XEN_CONSOLE_PROTOCOL_INTERNAL_H + + +#include "xen_internal.h" + + +extern const abstract_type xen_console_protocol_abstract_type_; +extern const abstract_type xen_console_protocol_set_abstract_type_; + + +#endif diff --git a/tools/libxen/include/xen_vm.h b/tools/libxen/include/xen_vm.h index f589a3eea5..522029f5ee 100644 --- a/tools/libxen/include/xen_vm.h +++ b/tools/libxen/include/xen_vm.h @@ -21,6 +21,7 @@ #include "xen_boot_type.h" #include "xen_common.h" +#include "xen_console_decl.h" #include "xen_cpu_feature.h" #include "xen_host_decl.h" #include "xen_int_float_map.h" @@ -96,6 +97,7 @@ typedef struct xen_vm_record enum xen_on_normal_exit actions_after_reboot; enum xen_on_normal_exit actions_after_suspend; enum xen_on_crash_behaviour actions_after_crash; + struct xen_console_record_opt_set *consoles; struct xen_vif_record_opt_set *vifs; struct xen_vbd_record_opt_set *vbds; struct xen_vtpm_record_opt_set *vtpms; @@ -400,6 +402,13 @@ extern bool xen_vm_get_actions_after_crash(xen_session *session, enum xen_on_crash_behaviour *result, xen_vm vm); +/** + * Get the consoles field of the given VM. + */ +extern bool +xen_vm_get_consoles(xen_session *session, struct xen_console_set **result, xen_vm vm); + + /** * Get the VIFs field of the given VM. */ diff --git a/tools/libxen/src/xen_console.c b/tools/libxen/src/xen_console.c new file mode 100644 index 0000000000..d33d927342 --- /dev/null +++ b/tools/libxen/src/xen_console.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2006, XenSource Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include +#include + +#include "xen_common.h" +#include "xen_console.h" +#include "xen_console_protocol_internal.h" +#include "xen_internal.h" +#include "xen_vm.h" + + +XEN_FREE(xen_console) +XEN_SET_ALLOC_FREE(xen_console) +XEN_ALLOC(xen_console_record) +XEN_SET_ALLOC_FREE(xen_console_record) +XEN_ALLOC(xen_console_record_opt) +XEN_RECORD_OPT_FREE(xen_console) +XEN_SET_ALLOC_FREE(xen_console_record_opt) + + +static const struct_member xen_console_record_struct_members[] = + { + { .key = "uuid", + .type = &abstract_type_string, + .offset = offsetof(xen_console_record, uuid) }, + { .key = "protocol", + .type = &xen_console_protocol_abstract_type_, + .offset = offsetof(xen_console_record, protocol) }, + { .key = "uri", + .type = &abstract_type_string, + .offset = offsetof(xen_console_record, uri) }, + { .key = "VM", + .type = &abstract_type_ref, + .offset = offsetof(xen_console_record, vm) } + }; + +const abstract_type xen_console_record_abstract_type_ = + { + .typename = STRUCT, + .struct_size = sizeof(xen_console_record), + .member_count = + sizeof(xen_console_record_struct_members) / sizeof(struct_member), + .members = xen_console_record_struct_members + }; + + +void +xen_console_record_free(xen_console_record *record) +{ + if (record == NULL) + { + return; + } + free(record->handle); + free(record->uuid); + free(record->uri); + xen_vm_record_opt_free(record->vm); + free(record); +} + + +bool +xen_console_get_record(xen_session *session, xen_console_record **result, xen_console console) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = console } + }; + + abstract_type result_type = xen_console_record_abstract_type_; + + *result = NULL; + XEN_CALL_("console.get_record"); + + if (session->ok) + { + (*result)->handle = xen_strdup_((*result)->uuid); + } + + return session->ok; +} + + +bool +xen_console_get_by_uuid(xen_session *session, xen_console *result, char *uuid) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = uuid } + }; + + abstract_type result_type = abstract_type_string; + + *result = NULL; + XEN_CALL_("console.get_by_uuid"); + return session->ok; +} + + +bool +xen_console_create(xen_session *session, xen_console *result, xen_console_record *record) +{ + abstract_value param_values[] = + { + { .type = &xen_console_record_abstract_type_, + .u.struct_val = record } + }; + + abstract_type result_type = abstract_type_string; + + *result = NULL; + XEN_CALL_("console.create"); + return session->ok; +} + + +bool +xen_console_destroy(xen_session *session, xen_console console) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = console } + }; + + xen_call_(session, "console.destroy", param_values, 1, NULL, NULL); + return session->ok; +} + + +bool +xen_console_get_protocol(xen_session *session, enum xen_console_protocol *result, xen_console console) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = console } + }; + + abstract_type result_type = xen_console_protocol_abstract_type_; + char *result_str = NULL; + XEN_CALL_("console.get_protocol"); + *result = xen_console_protocol_from_string(session, result_str); + return session->ok; +} + + +bool +xen_console_get_uri(xen_session *session, char **result, xen_console console) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = console } + }; + + abstract_type result_type = abstract_type_string; + + *result = NULL; + XEN_CALL_("console.get_uri"); + return session->ok; +} + + +bool +xen_console_get_vm(xen_session *session, xen_vm *result, xen_console console) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = console } + }; + + abstract_type result_type = abstract_type_string; + + *result = NULL; + XEN_CALL_("console.get_VM"); + return session->ok; +} + + +bool +xen_console_get_uuid(xen_session *session, char **result, xen_console console) +{ + *result = session->ok ? xen_strdup_((char *)console) : NULL; + return session->ok; +} diff --git a/tools/libxen/src/xen_console_protocol.c b/tools/libxen/src/xen_console_protocol.c new file mode 100644 index 0000000000..cb87ac01c9 --- /dev/null +++ b/tools/libxen/src/xen_console_protocol.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2006, XenSource Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include "xen_internal.h" +#include "xen_console_protocol.h" +#include "xen_console_protocol_internal.h" + + +/* + * Maintain this in the same order as the enum declaration! + */ +static const char *lookup_table[] = +{ + "vt100", + "rfb", + "rdp" +}; + + +extern xen_console_protocol_set * +xen_console_protocol_set_alloc(size_t size) +{ + return calloc(1, sizeof(xen_console_protocol_set) + + size * sizeof(enum xen_console_protocol)); +} + + +extern void +xen_console_protocol_set_free(xen_console_protocol_set *set) +{ + free(set); +} + + +const char * +xen_console_protocol_to_string(enum xen_console_protocol val) +{ + return lookup_table[val]; +} + + +extern enum xen_console_protocol +xen_console_protocol_from_string(xen_session *session, const char *str) +{ + return ENUM_LOOKUP(session, str, lookup_table); +} + + +const abstract_type xen_console_protocol_abstract_type_ = + { + .typename = ENUM, + .enum_marshaller = + (const char *(*)(int))&xen_console_protocol_to_string, + .enum_demarshaller = + (int (*)(xen_session *, const char *))&xen_console_protocol_from_string + }; + + +const abstract_type xen_console_protocol_set_abstract_type_ = + { + .typename = SET, + .child = &xen_console_protocol_abstract_type_ + }; + + diff --git a/tools/libxen/src/xen_vm.c b/tools/libxen/src/xen_vm.c index cd0271c71c..aac8d4006d 100644 --- a/tools/libxen/src/xen_vm.c +++ b/tools/libxen/src/xen_vm.c @@ -22,6 +22,7 @@ #include "xen_boot_type_internal.h" #include "xen_common.h" +#include "xen_console.h" #include "xen_cpu_feature.h" #include "xen_cpu_feature_internal.h" #include "xen_host.h" @@ -120,6 +121,9 @@ static const struct_member xen_vm_record_struct_members[] = { .key = "actions_after_crash", .type = &xen_on_crash_behaviour_abstract_type_, .offset = offsetof(xen_vm_record, actions_after_crash) }, + { .key = "consoles", + .type = &abstract_type_ref_set, + .offset = offsetof(xen_vm_record, consoles) }, { .key = "VIFs", .type = &abstract_type_ref_set, .offset = offsetof(xen_vm_record, vifs) }, @@ -205,6 +209,7 @@ xen_vm_record_free(xen_vm_record *record) xen_cpu_feature_set_free(record->vcpus_features_can_use); xen_cpu_feature_set_free(record->vcpus_features_force_on); xen_cpu_feature_set_free(record->vcpus_features_force_off); + xen_console_record_opt_set_free(record->consoles); xen_vif_record_opt_set_free(record->vifs); xen_vbd_record_opt_set_free(record->vbds); xen_vtpm_record_opt_set_free(record->vtpms); @@ -693,6 +698,23 @@ xen_vm_get_actions_after_crash(xen_session *session, enum xen_on_crash_behaviour } +bool +xen_vm_get_consoles(xen_session *session, struct xen_console_set **result, xen_vm vm) +{ + abstract_value param_values[] = + { + { .type = &abstract_type_string, + .u.string_val = vm } + }; + + abstract_type result_type = abstract_type_string_set; + + *result = NULL; + XEN_CALL_("VM.get_consoles"); + return session->ok; +} + + bool xen_vm_get_vifs(xen_session *session, struct xen_vif_set **result, xen_vm vm) { From 621fec4c37c4853f31d070e6c487d23cbe0737a8 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 23:34:33 +0000 Subject: [PATCH 066/282] State that getters and setters do not have asynchronous versions -- there's no point, because they ought to be immediate. Tidy up the examples in the presentation and wire-protocol sections, and bring them into sync with the main body text. Signed-off-by: Ewan Mellor --- docs/xen-api/presentation.tex | 5 +-- docs/xen-api/todo.tex | 2 ++ docs/xen-api/wire-protocol.tex | 62 +++++++++++----------------------- 3 files changed, 22 insertions(+), 47 deletions(-) diff --git a/docs/xen-api/presentation.tex b/docs/xen-api/presentation.tex index 0072704646..ba7ebdbde7 100644 --- a/docs/xen-api/presentation.tex +++ b/docs/xen-api/presentation.tex @@ -131,9 +131,6 @@ of that class that has the specified {\tt uuid}. ``{\tt get\_by\_name\_label(name)}'' RPC that returns a set of objects of that class that have the specified {\tt label}. -\item Each class has a ``{\tt to\_XML()}'' RPC that serialises the -state of all fields as an XML string. - \item Each class has a ``{\tt destroy(Ref x)}'' RPC that explicitly deletes the persistent object specified by {\tt x} from the system. This is a non-cascading delete -- if the object being removed is referenced by another @@ -144,6 +141,6 @@ object then the {\tt destroy} call will fail. \subsection{Additional RPCs} As well as the RPCs enumerated above, some classes have additional RPCs -associated with them. For example, the {\tt VM} class have RPCs for cloning, +associated with them. For example, the {\tt VM} class has RPCs for cloning, suspending, starting etc. Such additional RPCs are described explicitly in the API reference. diff --git a/docs/xen-api/todo.tex b/docs/xen-api/todo.tex index 2778ccce55..6f679ca01e 100644 --- a/docs/xen-api/todo.tex +++ b/docs/xen-api/todo.tex @@ -35,6 +35,8 @@ code, potential error description, but otherwise no value. \item Clarify behaviour of progress field on asyncrhonous request polling when that request fails. +\item Clarify which calls have asynchronous counterparts by marking them as such in the reference. (Individual getters and setters are too small and quick to justify having async versions) + \end{itemize} \subsection{Content} diff --git a/docs/xen-api/wire-protocol.tex b/docs/xen-api/wire-protocol.tex index ecd4ed9416..5b15573809 100644 --- a/docs/xen-api/wire-protocol.tex +++ b/docs/xen-api/wire-protocol.tex @@ -21,9 +21,9 @@ primitive XML-RPC types. In our API Reference we specify the signatures of API functions in the following style: \begin{verbatim} - (ref_vm Set) Host.ListAllVMs() + (ref_vm Set) VM.get_all() \end{verbatim} -This specifies that the function with name {\tt Host.ListAllVMs} takes +This specifies that the function with name {\tt VM.get\_all} takes no parameters and returns a Set of {\tt ref\_vm}s. These types are mapped onto XML-RPC types in a straight-forward manner: \begin{itemize} @@ -105,8 +105,8 @@ In the case where {\tt Status} is set to {\tt Failure} then the struct contains a second element named {\tt ErrorDescription}: \begin{itemize} \item The element of the struct named {\tt ErrorDescription} contains -an array of string values. The first element of the array represents an error code; -the remainder of the array represents error parameters relating to that code. +an array of string values. The first element of the array is an XML-RPC 32-bit {\tt i4} and represents an error code; +the remainder of the array are strings representing error parameters relating to that code. \end{itemize} For example, an XML-RPC return value from the {\tt Host.ListAllVMs} function above @@ -161,19 +161,19 @@ A session can be terminated with the {\tt Session.Logout} function: \subsection{Synchronous and Asynchronous invocation} -Each method call (apart from those on ``Session'' and ``Task'' objects) +Each method call (apart from methods on ``Session'' and ``Task'' objects +and ``getters'' and ``setters'' derived from fields) can be made either synchronously or asynchronously. A synchronous RPC call blocks until the return value is received; the return value of a synchronous RPC call is exactly as specified in Section~\ref{synchronous-result}. -Each of the methods specified in the API Reference is synchronous. -However, although not listed explicitly in this document, each -method call has an asynchronous analogue in the {\tt Async} -namespace. For example, synchronous call {\tt VM.Install(...)} +Only synchronous API calls are listed explicitly in this document. +All asynchronous versions are in the special {\tt Async} namespace. +For example, synchronous call {\tt VM.clone(...)} (described in Chapter~\ref{api-reference}) has an asynchronous counterpart, {\tt -Async.VM.Install(...)}, that is non-blocking. +Async.VM.clone(...)}, that is non-blocking. Instead of returning its result directly, an asynchronous RPC call returns a {\tt task-id}; this identifier is subsequently used @@ -186,39 +186,14 @@ is wrapped in an XML-RPC struct with a {\tt Status}, {\tt ErrorDescription} and The {\tt task-id} is provided in the {\tt Value} field if {\tt Status} is set to {\tt Success}. -Two special RPC calls are provided to poll the status of -asynchronous calls: +The RPC call \begin{verbatim} - Array Async.Task.GetAllTasks (session_id s) - task_status Async.Task.GetStatus (session_id s, task_id t) -\end{verbatim} - -{\tt Async.Task.GetAllTasks} returns a set of the currently -executing asynchronous tasks belong to the current user\footnote{ -% -The current user is determined by the username that was provided -to {\tt Session.Login}. -% -}. - -{\tt Async.Task.GetStatus} returns a {\tt task\_status} result. -This is an XML-RPC struct with three elements: -\begin{itemize} - \item The first element is named {\tt Progress} and contains -an {\tt Integer} between 0 and 100 representing the estimated percentage of -the task currently completed. - \item The second element is named {\tt ETA} and contains a {\tt DateTime} -representing the estimated time the task will be complete. - \item The third element is named {\tt Result}. If {\tt Progress} -is not 100 then {\tt Result} contains the empty string. If {\tt Progress} -{\em is\/} set to 100, then {\tt Result} contains the function's return -result (as specified in Section~\ref{synchronous-result})\footnote{ -% -Recall that this itself is a struct potentially containing status, errorcode, -value fields etc. -% -}. -\end{itemize} + (ref_task Set) Task.get_all(session_id s) +\end{verbatim} +returns a set of all task IDs known to the system. The status (including any +returned result and error codes) of these tasks +can then be queried by accessing the fields of the Task object in the usual way. +Note that, in order to get a consistent snapshot of a task's state, it is advisable to call the ``get\_record'' function. \section{Example interactive session} @@ -267,7 +242,8 @@ Next, the user may acquire a list of all the VMs known to the host: (Note the ca \begin{verbatim} >>> all_vms = xen.VM.do_list(session)['Value'] >>> all_vms -['b7b92d9e-d442-4710-92a5-ab039fd7d89b', '23e1e837-abbf-4675-b077-d4007989b0cc', '2045dbc0-0734-4eea-9cb2-b8218c6b5bf2', '3202ae18-a046-4c32-9fda-e32e9631866e'] +['b7b92d9e-d442-4710-92a5-ab039fd7d89b', '23e1e837-abbf-4675-b077-d4007989b0cc', + '2045dbc0-0734-4eea-9cb2-b8218c6b5bf2', '3202ae18-a046-4c32-9fda-e32e9631866e'] \end{verbatim} Note the VM references are internally UUIDs. Once a reference to a VM has been acquired a lifecycle operation may be invoked: From dc7f685195f2097d99c82bbd1a643024a95331b9 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 29 Nov 2006 23:40:40 +0000 Subject: [PATCH 067/282] Added the console class to the diagram. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel-graph.dot | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/xen-api/xenapi-datamodel-graph.dot b/docs/xen-api/xenapi-datamodel-graph.dot index 794d9ea17a..daeca1f6e5 100644 --- a/docs/xen-api/xenapi-datamodel-graph.dot +++ b/docs/xen-api/xenapi-datamodel-graph.dot @@ -1,5 +1,5 @@ digraph g{ -node [ shape=box ]; session [ URL="session.html" ] task [ URL="task.html" ] VM [ URL="VM.html" ] host [ URL="host.html" ] host_cpu [ URL="host_cpu.html" ] network [ URL="network.html" ] VIF [ URL="VIF.html" ] PIF [ URL="PIF.html" ] SR [ URL="SR.html" ] VDI [ URL="VDI.html" ] VBD [ URL="VBD.html" ] VTPM [ URL="VTPM.html" ] user [ URL="user.html" ] debug [ URL="debug.html" ]; +node [ shape=box ]; session [ URL="session.html" ] task [ URL="task.html" ] VM [ URL="VM.html" ] host [ URL="host.html" ] host_cpu [ URL="host_cpu.html" ] network [ URL="network.html" ] VIF [ URL="VIF.html" ] PIF [ URL="PIF.html" ] SR [ URL="SR.html" ] VDI [ URL="VDI.html" ] VBD [ URL="VBD.html" ] VTPM [ URL="VTPM.html" ] console [ URL="console.html" ] user [ URL="user.html" ] debug [ URL="debug.html" ]; session -> host [ label="this_host(1)" ] session -> user [ label="this_user(1)" ] host -> VM [ color="blue", arrowhead="crow", arrowtail="none" ] @@ -14,4 +14,5 @@ VDI -> VDI [ color="blue", arrowhead="none", arrowtail="crow" ] VBD -> VM [ color="blue", arrowhead="none", arrowtail="crow" ] VTPM -> VM [ label="backend(1)" ] VTPM -> VM [ color="blue", arrowhead="none", arrowtail="crow" ] +console -> VM [ color="blue", arrowhead="none", arrowtail="crow" ] } From 4f24c93f2e0bb7306ddcabdc5d7e13636396e917 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 10:57:28 +0000 Subject: [PATCH 068/282] [XEN] Simplify x86_emulate interface. - No distinction between 'special' and 'normal' memory accesses. - No reliance on caller-supplied %cr2 value - Memory operations include segment identifier to allow callers to support non-zero-based segments TODO: 1. HVM emulations should take into account segment base, limit, and attributes. 2. We ought to obey stack-size attribute on PUSH/POP instructions. Could extend the mode input field, or could add an extra call-out hook, or perhaps we don't care at all... Signed-off-by: Keir Fraser --- tools/tests/test_x86_emulator.c | 76 +++-- xen/arch/x86/mm.c | 95 ++++--- xen/arch/x86/mm/shadow/common.c | 88 +++--- xen/arch/x86/mm/shadow/multi.c | 1 - xen/arch/x86/x86_emulate.c | 459 +++++++++++++----------------- xen/include/asm-x86/x86_emulate.h | 113 +++----- 6 files changed, 375 insertions(+), 457 deletions(-) diff --git a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c index d3b7af0a7c..31f1abcb02 100644 --- a/tools/tests/test_x86_emulator.c +++ b/tools/tests/test_x86_emulator.c @@ -17,12 +17,14 @@ typedef int64_t s64; #define PFEC_write_access (1U<<1) -static int read_any( - unsigned long addr, +static int read( + unsigned int seg, + unsigned long offset, unsigned long *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + unsigned long addr = offset; switch ( bytes ) { case 1: *val = *(u8 *)addr; break; @@ -33,12 +35,14 @@ static int read_any( return X86EMUL_CONTINUE; } -static int write_any( - unsigned long addr, +static int write( + unsigned int seg, + unsigned long offset, unsigned long val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + unsigned long addr = offset; switch ( bytes ) { case 1: *(u8 *)addr = (u8)val; break; @@ -49,13 +53,15 @@ static int write_any( return X86EMUL_CONTINUE; } -static int cmpxchg_any( - unsigned long addr, +static int cmpxchg( + unsigned int seg, + unsigned long offset, unsigned long old, unsigned long new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + unsigned long addr = offset; switch ( bytes ) { case 1: *(u8 *)addr = (u8)new; break; @@ -66,21 +72,23 @@ static int cmpxchg_any( return X86EMUL_CONTINUE; } -static int cmpxchg8b_any( - unsigned long addr, +static int cmpxchg8b( + unsigned int seg, + unsigned long offset, unsigned long old_lo, unsigned long old_hi, unsigned long new_lo, unsigned long new_hi, struct x86_emulate_ctxt *ctxt) { + unsigned long addr = offset; ((unsigned long *)addr)[0] = new_lo; ((unsigned long *)addr)[1] = new_hi; return X86EMUL_CONTINUE; } static struct x86_emulate_ops emulops = { - read_any, write_any, read_any, write_any, cmpxchg_any, cmpxchg8b_any + read, write, cmpxchg, cmpxchg8b }; int main(int argc, char **argv) @@ -108,7 +116,7 @@ int main(int argc, char **argv) regs.eip = (unsigned long)&instr[0]; regs.ecx = 0x12345678; regs.error_code = PFEC_write_access; - ctxt.cr2 = (unsigned long)res; + regs.eax = (unsigned long)res; *res = 0x7FFFFFFF; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -127,7 +135,7 @@ int main(int argc, char **argv) #else regs.ecx = 0x12345678UL; #endif - ctxt.cr2 = (unsigned long)res; + regs.eax = (unsigned long)res; regs.error_code = 0; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -142,7 +150,7 @@ int main(int argc, char **argv) regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.ecx = ~0UL; - ctxt.cr2 = (unsigned long)res; + regs.eax = (unsigned long)res; regs.error_code = 0; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -152,13 +160,13 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); - printf("%-40s", "Testing lock cmpxchgb %%cl,(%%eax)..."); - instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x08; + printf("%-40s", "Testing lock cmpxchgb %%cl,(%%ebx)..."); + instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x0b; regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.eax = 0x92345677UL; regs.ecx = 0xAA; - ctxt.cr2 = (unsigned long)res; + regs.ebx = (unsigned long)res; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -169,13 +177,13 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); - printf("%-40s", "Testing lock cmpxchgb %%cl,(%%eax)..."); - instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x08; + printf("%-40s", "Testing lock cmpxchgb %%cl,(%%ebx)..."); + instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb0; instr[3] = 0x0b; regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.eax = 0xAABBCC77UL; regs.ecx = 0xFF; - ctxt.cr2 = (unsigned long)res; + regs.ebx = (unsigned long)res; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -192,7 +200,7 @@ int main(int argc, char **argv) regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.ecx = 0x12345678; - ctxt.cr2 = (unsigned long)res; + regs.eax = (unsigned long)res; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -203,14 +211,14 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); - printf("%-40s", "Testing lock cmpxchgl %%ecx,(%%eax)..."); - instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb1; instr[3] = 0x08; + printf("%-40s", "Testing lock cmpxchgl %%ecx,(%%ebx)..."); + instr[0] = 0xf0; instr[1] = 0x0f; instr[2] = 0xb1; instr[3] = 0x0b; regs.eflags = 0x200; *res = 0x923456AA; regs.eip = (unsigned long)&instr[0]; regs.eax = 0x923456AAUL; regs.ecx = 0xDDEEFF00L; - ctxt.cr2 = (unsigned long)res; + regs.ebx = (unsigned long)res; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -230,7 +238,6 @@ int main(int argc, char **argv) regs.esi = (unsigned long)res + 0; regs.edi = (unsigned long)res + 2; regs.error_code = 0; /* read fault */ - ctxt.cr2 = regs.esi; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || (*res != 0x44554455) || @@ -248,7 +255,6 @@ int main(int argc, char **argv) regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.edi = (unsigned long)res; - ctxt.cr2 = regs.edi; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -258,6 +264,22 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); + printf("%-40s", "Testing btrl %eax,(%edi)..."); + instr[0] = 0x0f; instr[1] = 0xb3; instr[2] = 0x07; + *res = 0x2233445F; + regs.eflags = 0x200; + regs.eip = (unsigned long)&instr[0]; + regs.eax = -32; + regs.edi = (unsigned long)(res+1); + regs.error_code = PFEC_write_access; + rc = x86_emulate_memop(&ctxt, &emulops); + if ( (rc != 0) || + (*res != 0x2233445E) || + ((regs.eflags&0x201) != 0x201) || + (regs.eip != (unsigned long)&instr[3]) ) + goto fail; + printf("okay\n"); + res[0] = 0x12345678; res[1] = 0x87654321; @@ -270,7 +292,6 @@ int main(int argc, char **argv) regs.ecx = 0xCCCCFFFF; regs.eip = (unsigned long)&instr[0]; regs.edi = (unsigned long)res; - ctxt.cr2 = regs.edi; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -285,7 +306,6 @@ int main(int argc, char **argv) instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f; regs.eip = (unsigned long)&instr[0]; regs.edi = (unsigned long)res; - ctxt.cr2 = regs.edi; regs.error_code = PFEC_write_access; rc = x86_emulate_memop(&ctxt, &emulops); if ( (rc != 0) || @@ -302,7 +322,7 @@ int main(int argc, char **argv) instr[0] = 0x0f; instr[1] = 0xbe; instr[2] = 0x08; regs.eip = (unsigned long)&instr[0]; regs.ecx = 0x12345678; - ctxt.cr2 = (unsigned long)res; + regs.eax = (unsigned long)res; *res = 0x82; regs.error_code = 0; rc = x86_emulate_memop(&ctxt, &emulops); @@ -318,7 +338,7 @@ int main(int argc, char **argv) instr[0] = 0x0f; instr[1] = 0xb7; instr[2] = 0x08; regs.eip = (unsigned long)&instr[0]; regs.ecx = 0x12345678; - ctxt.cr2 = (unsigned long)res; + regs.eax = (unsigned long)res; *res = 0x1234aa82; regs.error_code = 0; rc = x86_emulate_memop(&ctxt, &emulops); diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 6980960a71..24a43663ae 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3033,12 +3033,39 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) * Writable Pagetables */ +struct ptwr_emulate_ctxt { + struct x86_emulate_ctxt ctxt; + unsigned long cr2; + l1_pgentry_t pte; +}; + +static int ptwr_emulated_read( + unsigned int seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + unsigned int rc; + unsigned long addr = offset; + + *val = 0; + if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 ) + { + propagate_page_fault(addr + bytes - rc, 0); /* read fault */ + return X86EMUL_PROPAGATE_FAULT; + } + + return X86EMUL_CONTINUE; +} + static int ptwr_emulated_update( unsigned long addr, paddr_t old, paddr_t val, unsigned int bytes, - unsigned int do_cmpxchg) + unsigned int do_cmpxchg, + struct ptwr_emulate_ctxt *ptwr_ctxt) { unsigned long gmfn, mfn; struct page_info *page; @@ -3046,11 +3073,11 @@ static int ptwr_emulated_update( struct vcpu *v = current; struct domain *d = v->domain; - /* Aligned access only, thank you. */ - if ( !access_ok(addr, bytes) || ((addr & (bytes-1)) != 0) ) + /* Only allow naturally-aligned stores within the original %cr2 page. */ + if ( unlikely(((addr^ptwr_ctxt->cr2) & PAGE_MASK) || (addr & (bytes-1))) ) { - MEM_LOG("ptwr_emulate: Unaligned or bad size ptwr access (%d, %lx)", - bytes, addr); + MEM_LOG("Bad ptwr access (cr2=%lx, addr=%lx, bytes=%u)", + ptwr_ctxt->cr2, addr, bytes); return X86EMUL_UNHANDLEABLE; } @@ -3079,17 +3106,9 @@ static int ptwr_emulated_update( old |= full; } - /* Read the PTE that maps the page being updated. */ - guest_get_eff_l1e(v, addr, &pte); - if ( unlikely(!(l1e_get_flags(pte) & _PAGE_PRESENT)) ) - { - MEM_LOG("%s: Cannot get L1 PTE for guest address %lx", - __func__, addr); - return X86EMUL_UNHANDLEABLE; - } - - gmfn = l1e_get_pfn(pte); - mfn = gmfn_to_mfn(d, gmfn); + pte = ptwr_ctxt->pte; + gmfn = l1e_get_pfn(pte); + mfn = gmfn_to_mfn(d, gmfn); page = mfn_to_page(mfn); /* We are looking only for read-only mappings of p.t. pages. */ @@ -3164,26 +3183,33 @@ static int ptwr_emulated_update( } static int ptwr_emulated_write( - unsigned long addr, + unsigned int seg, + unsigned long offset, unsigned long val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - return ptwr_emulated_update(addr, 0, val, bytes, 0); + return ptwr_emulated_update( + offset, 0, val, bytes, 0, + container_of(ctxt, struct ptwr_emulate_ctxt, ctxt)); } static int ptwr_emulated_cmpxchg( - unsigned long addr, + unsigned int seg, + unsigned long offset, unsigned long old, unsigned long new, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - return ptwr_emulated_update(addr, old, new, bytes, 1); + return ptwr_emulated_update( + offset, old, new, bytes, 1, + container_of(ctxt, struct ptwr_emulate_ctxt, ctxt)); } static int ptwr_emulated_cmpxchg8b( - unsigned long addr, + unsigned int seg, + unsigned long offset, unsigned long old, unsigned long old_hi, unsigned long new, @@ -3192,18 +3218,16 @@ static int ptwr_emulated_cmpxchg8b( { if ( CONFIG_PAGING_LEVELS == 2 ) return X86EMUL_UNHANDLEABLE; - else - return ptwr_emulated_update( - addr, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1); + return ptwr_emulated_update( + offset, ((u64)old_hi << 32) | old, ((u64)new_hi << 32) | new, 8, 1, + container_of(ctxt, struct ptwr_emulate_ctxt, ctxt)); } static struct x86_emulate_ops ptwr_emulate_ops = { - .read_std = x86_emulate_read_std, - .write_std = x86_emulate_write_std, - .read_emulated = x86_emulate_read_std, - .write_emulated = ptwr_emulated_write, - .cmpxchg_emulated = ptwr_emulated_cmpxchg, - .cmpxchg8b_emulated = ptwr_emulated_cmpxchg8b + .read = ptwr_emulated_read, + .write = ptwr_emulated_write, + .cmpxchg = ptwr_emulated_cmpxchg, + .cmpxchg8b = ptwr_emulated_cmpxchg8b }; /* Write page fault handler: check if guest is trying to modify a PTE. */ @@ -3214,7 +3238,7 @@ int ptwr_do_page_fault(struct vcpu *v, unsigned long addr, unsigned long pfn; struct page_info *page; l1_pgentry_t pte; - struct x86_emulate_ctxt emul_ctxt; + struct ptwr_emulate_ctxt ptwr_ctxt; LOCK_BIGLOCK(d); @@ -3235,10 +3259,11 @@ int ptwr_do_page_fault(struct vcpu *v, unsigned long addr, (page_get_owner(page) != d) ) goto bail; - emul_ctxt.regs = guest_cpu_user_regs(); - emul_ctxt.cr2 = addr; - emul_ctxt.mode = X86EMUL_MODE_HOST; - if ( x86_emulate_memop(&emul_ctxt, &ptwr_emulate_ops) ) + ptwr_ctxt.ctxt.regs = guest_cpu_user_regs(); + ptwr_ctxt.ctxt.mode = X86EMUL_MODE_HOST; + ptwr_ctxt.cr2 = addr; + ptwr_ctxt.pte = pte; + if ( x86_emulate_memop(&ptwr_ctxt.ctxt, &ptwr_emulate_ops) ) goto bail; UNLOCK_BIGLOCK(d); diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index cad0ea4cc9..539f81f947 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -70,11 +70,14 @@ int _shadow_mode_refcounts(struct domain *d) */ static int -sh_x86_emulate_read_std(unsigned long addr, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) +sh_x86_emulate_read(unsigned int seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) { + unsigned long addr = offset; + *val = 0; // XXX -- this is WRONG. // It entirely ignores the permissions in the page tables. @@ -99,40 +102,15 @@ sh_x86_emulate_read_std(unsigned long addr, } static int -sh_x86_emulate_write_std(unsigned long addr, - unsigned long val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ -#if 0 - struct vcpu *v = current; - SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n", - v->domain->domain_id, v->vcpu_id, addr, val, bytes); -#endif - - // XXX -- this is WRONG. - // It entirely ignores the permissions in the page tables. - // In this case, that includes user vs supervisor, and - // write access. - // - if ( hvm_copy_to_guest_virt(addr, &val, bytes) == 0 ) - return X86EMUL_CONTINUE; - - /* If we got here, there was nothing mapped here, or a bad GFN - * was mapped here. This should never happen: we're here because - * of a write fault at the end of the instruction we're emulating, - * which should be handled by sh_x86_emulate_write_emulated. */ - SHADOW_PRINTK("write failed to va %#lx\n", addr); - return X86EMUL_PROPAGATE_FAULT; -} - -static int -sh_x86_emulate_write_emulated(unsigned long addr, - unsigned long val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) +sh_x86_emulate_write(unsigned int seg, + unsigned long offset, + unsigned long val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) { struct vcpu *v = current; + unsigned long addr = offset; + #if 0 SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n", v->domain->domain_id, v->vcpu_id, addr, val, bytes); @@ -141,13 +119,16 @@ sh_x86_emulate_write_emulated(unsigned long addr, } static int -sh_x86_emulate_cmpxchg_emulated(unsigned long addr, - unsigned long old, - unsigned long new, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) +sh_x86_emulate_cmpxchg(unsigned int seg, + unsigned long offset, + unsigned long old, + unsigned long new, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) { struct vcpu *v = current; + unsigned long addr = offset; + #if 0 SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n", v->domain->domain_id, v->vcpu_id, addr, old, new, bytes); @@ -157,14 +138,17 @@ sh_x86_emulate_cmpxchg_emulated(unsigned long addr, } static int -sh_x86_emulate_cmpxchg8b_emulated(unsigned long addr, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) +sh_x86_emulate_cmpxchg8b(unsigned int seg, + unsigned long offset, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi, + struct x86_emulate_ctxt *ctxt) { struct vcpu *v = current; + unsigned long addr = offset; + #if 0 SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx:%lx n:=%#lx:%lx\n", v->domain->domain_id, v->vcpu_id, addr, old_hi, old_lo, @@ -176,12 +160,10 @@ sh_x86_emulate_cmpxchg8b_emulated(unsigned long addr, struct x86_emulate_ops shadow_emulator_ops = { - .read_std = sh_x86_emulate_read_std, - .write_std = sh_x86_emulate_write_std, - .read_emulated = sh_x86_emulate_read_std, - .write_emulated = sh_x86_emulate_write_emulated, - .cmpxchg_emulated = sh_x86_emulate_cmpxchg_emulated, - .cmpxchg8b_emulated = sh_x86_emulate_cmpxchg8b_emulated, + .read = sh_x86_emulate_read, + .write = sh_x86_emulate_write, + .cmpxchg = sh_x86_emulate_cmpxchg, + .cmpxchg8b = sh_x86_emulate_cmpxchg8b, }; /**************************************************************************/ diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index c582b82b51..efb1f0933d 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -2812,7 +2812,6 @@ static int sh_page_fault(struct vcpu *v, if ( is_hvm_domain(d) ) hvm_store_cpu_guest_regs(v, regs, NULL); emul_ctxt.regs = regs; - emul_ctxt.cr2 = va; emul_ctxt.mode = (is_hvm_domain(d) ? hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST); diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 7fb5875a91..22f63222f7 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -15,9 +15,9 @@ #include #include #include -#include #include #define dprintf(_f, _a...) gdprintk(XENLOG_WARNING, _f , ## _a ) +#undef cmpxchg #endif #include @@ -38,6 +38,7 @@ /* Operand sizes: 8-bit operands or specified/overridden size. */ #define ByteOp (1<<0) /* 8-bit operands. */ /* Destination operand type. */ +#define DstBitBase (0<<1) /* Memory operand, bit string. */ #define ImplicitOps (1<<1) /* Implicit in opcode. No generic decode. */ #define DstReg (2<<1) /* Register operand. */ #define DstMem (3<<1) /* Memory operand. */ @@ -111,8 +112,8 @@ static uint8_t opcode_table[256] = { /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ - ByteOp|DstReg|SrcMem|Mov, DstReg|SrcMem|Mov, - ByteOp|DstMem|SrcReg|Mov, DstMem|SrcReg|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, + ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, 0, 0, /* 0xA8 - 0xAF */ 0, 0, ByteOp|ImplicitOps|Mov, ImplicitOps|Mov, @@ -170,14 +171,15 @@ static uint8_t twobyte_table[256] = { /* 0x90 - 0x9F */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xA0 - 0xA7 */ - 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, /* 0xA8 - 0xAF */ - 0, 0, 0, DstMem|SrcReg|ModRM, 0, 0, 0, 0, + 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, /* 0xB0 - 0xB7 */ - ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstMem|SrcReg|ModRM, + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, + 0, DstBitBase|SrcReg|ModRM, 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, /* 0xB8 - 0xBF */ - 0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, + 0, 0, DstBitBase|SrcImmByte|ModRM, DstBitBase|SrcReg|ModRM, 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, /* 0xC0 - 0xCF */ 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0, @@ -193,7 +195,12 @@ static uint8_t twobyte_table[256] = { struct operand { enum { OP_REG, OP_MEM, OP_IMM } type; unsigned int bytes; - unsigned long val, orig_val, *ptr; + unsigned long val, orig_val; + /* OP_REG: Pointer to register field. */ + unsigned long *reg; + /* OP_MEM: Segment and offset. */ + unsigned int mem_seg; + unsigned long mem_off; }; /* EFLAGS bit definitions. */ @@ -366,24 +373,23 @@ do{ __asm__ __volatile__ ( \ #endif /* __i386__ */ /* Fetch next part of the instruction being emulated. */ -#define _insn_fetch(_size) \ -({ unsigned long _x, _ptr = _regs.eip; \ - if ( mode == X86EMUL_MODE_REAL ) _ptr += _regs.cs << 4; \ - rc = ops->read_std(_ptr, &_x, (_size), ctxt); \ - if ( rc != 0 ) \ - goto done; \ - _regs.eip += (_size); \ - _x; \ +#define _insn_fetch(_size) \ +({ unsigned long _x; \ + rc = ops->read(_regs.cs, _regs.eip, &_x, (_size), ctxt); \ + if ( rc != 0 ) \ + goto done; \ + _regs.eip += (_size); \ + _x; \ }) #define insn_fetch(_type) ((_type)_insn_fetch(sizeof(_type))) -/* Access/update address held in a register, based on addressing mode. */ -#define register_address(sel, reg) \ -({ unsigned long __reg = (reg); \ - (((mode == X86EMUL_MODE_REAL) ? ((unsigned long)(sel) << 4) : 0) + \ - ((ad_bytes == sizeof(unsigned long)) ? __reg : \ - (__reg & ((1UL << (ad_bytes << 3)) - 1)))); \ +#define truncate_ea(ea) \ +({ unsigned long __ea = (ea); \ + ((ad_bytes == sizeof(unsigned long)) ? __ea : \ + (__ea & ((1UL << (ad_bytes << 3)) - 1))); \ }) + +/* Update address held in a register, based on addressing mode. */ #define register_address_increment(reg, inc) \ do { \ int _inc = (inc); /* signed type ensures sign extension to long */ \ @@ -394,17 +400,6 @@ do { \ (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \ } while (0) -/* - * We cannot handle a page fault on a data access that straddles two pages - * and faults on the second page. This is because CR2 is not equal to the - * memory operand's effective address in this case. Rather than fix up the - * effective address it is okay for us to fail the emulation. - */ -#define page_boundary_test() do { \ - if ( ((cr2 & (PAGE_SIZE-1)) == 0) && ((ea & 7) != 0) ) \ - goto bad_ea; \ -} while ( 0 ) - void * decode_register( uint8_t modrm_reg, struct cpu_user_regs *regs, int highbyte_regs) @@ -452,16 +447,12 @@ dump_instr( { #ifdef __XEN__ int i; - unsigned long x, pc; - - pc = ctxt->regs->eip; - if ( ctxt->mode == X86EMUL_MODE_REAL ) - pc += ctxt->regs->cs << 4; + unsigned long x, eip = ctxt->regs->eip; dprintf("Instr:"); - for ( i = 0; i < 16; i++, pc++ ) + for ( i = 0; i < 16; i++, eip++ ) { - if ( ops->read_std(pc, &x, 1, ctxt) != 0 ) + if ( ops->read(ctxt->regs->cs, eip, &x, 1, ctxt) != 0 ) printk(" ??"); else printk(" %02x", (uint8_t)x); @@ -480,19 +471,13 @@ x86_emulate_memop( uint8_t b, d, sib, sib_index, sib_base, twobyte = 0, rex_prefix = 0; uint8_t modrm, modrm_mod = 0, modrm_reg = 0, modrm_rm = 0; - uint16_t *seg = &_regs.ds; /* override segment */ unsigned int op_bytes, ad_bytes, lock_prefix = 0, rep_prefix = 0, i; int rc = 0; struct operand src, dst; - unsigned long ea = 0, cr2 = ctxt->cr2; int mode = ctxt->mode; - /* - * We do not emulate faults on instruction fetch. We assume that the - * guest never executes out of a special memory area. - */ - if ( _regs.error_code & PFEC_insn_fetch ) - return -1; + unsigned int ea_seg = X86_SEG_DS; + unsigned long ea_off = 0; switch ( mode ) { @@ -528,22 +513,22 @@ x86_emulate_memop( ad_bytes ^= 6; /* switch between 2/4 bytes */ break; case 0x2e: /* CS override */ - seg = &_regs.cs; + ea_seg = X86_SEG_CS; break; case 0x3e: /* DS override */ - seg = &_regs.ds; + ea_seg = X86_SEG_DS; break; case 0x26: /* ES override */ - seg = &_regs.es; + ea_seg = X86_SEG_ES; break; case 0x64: /* FS override */ - seg = &_regs.fs; + ea_seg = X86_SEG_FS; break; case 0x65: /* GS override */ - seg = &_regs.gs; + ea_seg = X86_SEG_GS; break; case 0x36: /* SS override */ - seg = &_regs.ss; + ea_seg = X86_SEG_SS; break; case 0xf0: /* LOCK */ lock_prefix = 1; @@ -604,20 +589,20 @@ x86_emulate_memop( /* 16-bit ModR/M decode. */ switch ( modrm_rm ) { - case 0: ea = _regs.ebx + _regs.esi; break; - case 1: ea = _regs.ebx + _regs.edi; break; - case 2: ea = _regs.ebp + _regs.esi; break; - case 3: ea = _regs.ebp + _regs.edi; break; - case 4: ea = _regs.esi; break; - case 5: ea = _regs.edi; break; - case 6: ea = _regs.ebp; break; - case 7: ea = _regs.ebx; break; + case 0: ea_off = _regs.ebx + _regs.esi; break; + case 1: ea_off = _regs.ebx + _regs.edi; break; + case 2: ea_off = _regs.ebp + _regs.esi; break; + case 3: ea_off = _regs.ebp + _regs.edi; break; + case 4: ea_off = _regs.esi; break; + case 5: ea_off = _regs.edi; break; + case 6: ea_off = _regs.ebp; break; + case 7: ea_off = _regs.ebx; break; } switch ( modrm_mod ) { - case 0: if ( modrm_rm == 6 ) ea = insn_fetch(int16_t); break; - case 1: ea += insn_fetch(int8_t); break; - case 2: ea += insn_fetch(int16_t); break; + case 0: if ( modrm_rm == 6 ) ea_off = insn_fetch(int16_t); break; + case 1: ea_off += insn_fetch(int8_t); break; + case 2: ea_off += insn_fetch(int16_t); break; } } else @@ -629,83 +614,50 @@ x86_emulate_memop( sib_index = ((sib >> 3) & 7) | ((modrm << 2) & 8); sib_base = (sib & 7) | ((modrm << 3) & 8); if ( sib_index != 4 ) - ea = *(long *)decode_register(sib_index, &_regs, 0); - ea <<= (sib >> 6) & 3; + ea_off = *(long *)decode_register(sib_index, &_regs, 0); + ea_off <<= (sib >> 6) & 3; if ( (modrm_mod == 0) && ((sib_base & 7) == 5) ) - ea += insn_fetch(int32_t); + ea_off += insn_fetch(int32_t); else - ea += *(long *)decode_register(sib_base, &_regs, 0); + ea_off += *(long *)decode_register(sib_base, &_regs, 0); } else { modrm_rm |= (rex_prefix & 1) << 3; - ea = *(long *)decode_register(modrm_rm, &_regs, 0); + ea_off = *(long *)decode_register(modrm_rm, &_regs, 0); } switch ( modrm_mod ) { case 0: if ( (modrm_rm & 7) != 5 ) break; - ea = insn_fetch(int32_t); + ea_off = insn_fetch(int32_t); if ( mode != X86EMUL_MODE_PROT64 ) break; /* Relative to RIP of next instruction. Argh! */ - ea += _regs.eip; + ea_off += _regs.eip; if ( (d & SrcMask) == SrcImm ) - ea += (d & ByteOp) ? 1 : ((op_bytes == 8) ? 4 : op_bytes); + ea_off += (d & ByteOp) ? 1 : + ((op_bytes == 8) ? 4 : op_bytes); else if ( (d & SrcMask) == SrcImmByte ) - ea += 1; + ea_off += 1; else if ( ((b == 0xf6) || (b == 0xf7)) && ((modrm_reg & 7) <= 1) ) /* Special case in Grp3: test has immediate operand. */ - ea += (d & ByteOp) ? 1 + ea_off += (d & ByteOp) ? 1 : ((op_bytes == 8) ? 4 : op_bytes); break; - case 1: ea += insn_fetch(int8_t); break; - case 2: ea += insn_fetch(int32_t); break; + case 1: ea_off += insn_fetch(int8_t); break; + case 2: ea_off += insn_fetch(int32_t); break; } } - ea = register_address(*seg, ea); - page_boundary_test(); + ea_off = truncate_ea(ea_off); } - /* Decode and fetch the destination operand: register or memory. */ - switch ( d & DstMask ) - { - case ImplicitOps: - /* Special instructions do their own operand decoding. */ + /* Special instructions do their own operand decoding. */ + if ( (d & DstMask) == ImplicitOps ) goto special_insn; - case DstReg: - dst.type = OP_REG; - if ( d & ByteOp ) - { - dst.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); - dst.val = *(uint8_t *)dst.ptr; - dst.bytes = 1; - } - else - { - dst.ptr = decode_register(modrm_reg, &_regs, 0); - switch ( (dst.bytes = op_bytes) ) - { - case 2: dst.val = *(uint16_t *)dst.ptr; break; - case 4: dst.val = *(uint32_t *)dst.ptr; break; - case 8: dst.val = *(uint64_t *)dst.ptr; break; - } - } - break; - case DstMem: - dst.type = OP_MEM; - dst.ptr = (unsigned long *)cr2; - dst.bytes = (d & ByteOp) ? 1 : op_bytes; - if ( !(d & Mov) && /* optimisation - avoid slow emulated read */ - ((rc = ops->read_emulated((unsigned long)dst.ptr, - &dst.val, dst.bytes, ctxt)) != 0) ) - goto done; - break; - } - dst.orig_val = dst.val; /* Decode and fetch the source operand: register, memory or immediate. */ switch ( d & SrcMask ) @@ -716,18 +668,18 @@ x86_emulate_memop( src.type = OP_REG; if ( d & ByteOp ) { - src.ptr = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); - src.val = src.orig_val = *(uint8_t *)src.ptr; + src.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); + src.val = src.orig_val = *(uint8_t *)src.reg; src.bytes = 1; } else { - src.ptr = decode_register(modrm_reg, &_regs, 0); + src.reg = decode_register(modrm_reg, &_regs, 0); switch ( (src.bytes = op_bytes) ) { - case 2: src.val = src.orig_val = *(uint16_t *)src.ptr; break; - case 4: src.val = src.orig_val = *(uint32_t *)src.ptr; break; - case 8: src.val = src.orig_val = *(uint64_t *)src.ptr; break; + case 2: src.val = src.orig_val = *(uint16_t *)src.reg; break; + case 4: src.val = src.orig_val = *(uint32_t *)src.reg; break; + case 8: src.val = src.orig_val = *(uint64_t *)src.reg; break; } } break; @@ -741,15 +693,15 @@ x86_emulate_memop( src.bytes = (d & ByteOp) ? 1 : op_bytes; srcmem_common: src.type = OP_MEM; - src.ptr = (unsigned long *)cr2; - if ( (rc = ops->read_emulated((unsigned long)src.ptr, - &src.val, src.bytes, ctxt)) != 0 ) + src.mem_seg = ea_seg; + src.mem_off = ea_off; + if ( (rc = ops->read(src.mem_seg, src.mem_off, + &src.val, src.bytes, ctxt)) != 0 ) goto done; src.orig_val = src.val; break; case SrcImm: src.type = OP_IMM; - src.ptr = (unsigned long *)_regs.eip; src.bytes = (d & ByteOp) ? 1 : op_bytes; if ( src.bytes == 8 ) src.bytes = 4; /* NB. Immediates are sign-extended as necessary. */ @@ -762,12 +714,81 @@ x86_emulate_memop( break; case SrcImmByte: src.type = OP_IMM; - src.ptr = (unsigned long *)_regs.eip; src.bytes = 1; src.val = insn_fetch(int8_t); break; } + /* Decode and fetch the destination operand: register or memory. */ + switch ( d & DstMask ) + { + case DstReg: + dst.type = OP_REG; + if ( d & ByteOp ) + { + dst.reg = decode_register(modrm_reg, &_regs, (rex_prefix == 0)); + dst.val = *(uint8_t *)dst.reg; + dst.bytes = 1; + } + else + { + dst.reg = decode_register(modrm_reg, &_regs, 0); + switch ( (dst.bytes = op_bytes) ) + { + case 2: dst.val = *(uint16_t *)dst.reg; break; + case 4: dst.val = *(uint32_t *)dst.reg; break; + case 8: dst.val = *(uint64_t *)dst.reg; break; + } + } + break; + case DstBitBase: + dst.mem_off = ea_off; + if ( (d & SrcMask) == SrcImmByte ) + { + src.val &= (op_bytes << 3) - 1; + } + else + { + /* + * EA += BitOffset DIV op_bytes*8 + * BitOffset = BitOffset MOD op_byte*8 + * DIV truncates towards negative infinity. + * MOD always produces a positive result. + */ + if ( op_bytes == 2 ) + src.val = (int16_t)src.val; + else if ( op_bytes == 4 ) + src.val = (int32_t)src.val; + if ( (long)src.val < 0 ) + { + unsigned long byte_offset; + byte_offset = op_bytes + (((-src.val-1) >> 3) & ~(op_bytes-1)); + dst.mem_off -= byte_offset; + src.val = (byte_offset << 3) + src.val; + } + else + { + dst.mem_off += (src.val >> 3) & ~(op_bytes - 1); + src.val &= (op_bytes << 3) - 1; + } + } + /* Becomes a normal DstMem operation from here on. */ + d = (d & ~DstMask) | DstMem; + goto dstmem_common; + case DstMem: + dst.mem_off = ea_off; + dstmem_common: + dst.mem_seg = ea_seg; + dst.type = OP_MEM; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( !(d & Mov) && /* optimisation - avoid slow emulated read */ + ((rc = ops->read(dst.mem_seg, dst.mem_off, + &dst.val, dst.bytes, ctxt)) != 0) ) + goto done; + break; + } + dst.orig_val = dst.val; + if ( twobyte ) goto twobyte_insn; @@ -822,45 +843,25 @@ x86_emulate_memop( /* Write back the register source. */ switch ( dst.bytes ) { - case 1: *(uint8_t *)src.ptr = (uint8_t)dst.val; break; - case 2: *(uint16_t *)src.ptr = (uint16_t)dst.val; break; - case 4: *src.ptr = (uint32_t)dst.val; break; /* 64b reg: zero-extend */ - case 8: *src.ptr = dst.val; break; + case 1: *(uint8_t *)src.reg = (uint8_t)dst.val; break; + case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break; + case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */ + case 8: *src.reg = dst.val; break; } /* Write back the memory destination with implicit LOCK prefix. */ dst.val = src.val; lock_prefix = 1; break; - case 0xa0 ... 0xa1: /* mov */ - dst.ptr = (unsigned long *)&_regs.eax; - dst.val = src.val; - /* Source EA is not encoded via ModRM. */ - ea = register_address(*seg, _insn_fetch(ad_bytes)); - page_boundary_test(); - break; - case 0xa2 ... 0xa3: /* mov */ - dst.val = (unsigned long)_regs.eax; - /* Destination EA is not encoded via ModRM. */ - ea = register_address(*seg, _insn_fetch(ad_bytes)); - page_boundary_test(); - break; case 0x88 ... 0x8b: /* mov */ case 0xc6 ... 0xc7: /* mov (sole member of Grp11) */ dst.val = src.val; break; case 0x8f: /* pop (sole member of Grp1a) */ - /* - * If the faulting access was a read it means that the fault occurred - * when accessing the implicit stack operand. We assume the guest never - * uses special memory areas as stack space. - */ - if ( !(_regs.error_code & PFEC_write_access) ) - goto cannot_emulate; /* fault on stack access: bail */ /* 64-bit mode: POP always pops a 64-bit operand. */ if ( mode == X86EMUL_MODE_PROT64 ) dst.bytes = 8; - if ( (rc = ops->read_std(register_address(_regs.ss, _regs.esp), - &dst.val, dst.bytes, ctxt)) != 0 ) + if ( (rc = ops->read(X86_SEG_SS, truncate_ea(_regs.esp), + &dst.val, dst.bytes, ctxt)) != 0 ) goto done; register_address_increment(_regs.esp, dst.bytes); break; @@ -903,7 +904,6 @@ x86_emulate_memop( case 0 ... 1: /* test */ /* Special case in Grp3: test has an immediate source operand. */ src.type = OP_IMM; - src.ptr = (unsigned long *)_regs.eip; src.bytes = (d & ByteOp) ? 1 : op_bytes; if ( src.bytes == 8 ) src.bytes = 4; switch ( src.bytes ) @@ -933,24 +933,17 @@ x86_emulate_memop( emulate_1op("dec", dst, _regs.eflags); break; case 6: /* push */ - /* - * If the faulting access was a write it means that the fault - * occurred when accessing the implicit stack operand. We assume - * the guest never uses special memory areas as stack space. - */ - if ( _regs.error_code & PFEC_write_access ) - goto cannot_emulate; /* fault on stack access: bail */ /* 64-bit mode: PUSH always pushes a 64-bit operand. */ if ( mode == X86EMUL_MODE_PROT64 ) { dst.bytes = 8; - if ( (rc = ops->read_std((unsigned long)dst.ptr, - &dst.val, 8, ctxt)) != 0 ) + if ( (rc = ops->read(dst.mem_seg, dst.mem_off, + &dst.val, 8, ctxt)) != 0 ) goto done; } register_address_increment(_regs.esp, -dst.bytes); - if ( (rc = ops->write_std(register_address(_regs.ss, _regs.esp), - dst.val, dst.bytes, ctxt)) != 0 ) + if ( (rc = ops->write(X86_SEG_SS, truncate_ea(_regs.esp), + dst.val, dst.bytes, ctxt)) != 0 ) goto done; dst.val = dst.orig_val; /* skanky: disable writeback */ break; @@ -969,20 +962,20 @@ x86_emulate_memop( /* The 4-byte case *is* correct: in 64-bit mode we zero-extend. */ switch ( dst.bytes ) { - case 1: *(uint8_t *)dst.ptr = (uint8_t)dst.val; break; - case 2: *(uint16_t *)dst.ptr = (uint16_t)dst.val; break; - case 4: *dst.ptr = (uint32_t)dst.val; break; /* 64b: zero-ext */ - case 8: *dst.ptr = dst.val; break; + case 1: *(uint8_t *)dst.reg = (uint8_t)dst.val; break; + case 2: *(uint16_t *)dst.reg = (uint16_t)dst.val; break; + case 4: *dst.reg = (uint32_t)dst.val; break; /* 64b: zero-ext */ + case 8: *dst.reg = dst.val; break; } break; case OP_MEM: if ( lock_prefix ) - rc = ops->cmpxchg_emulated( - (unsigned long)dst.ptr, dst.orig_val, + rc = ops->cmpxchg( + dst.mem_seg, dst.mem_off, dst.orig_val, dst.val, dst.bytes, ctxt); else - rc = ops->write_emulated( - (unsigned long)dst.ptr, dst.val, dst.bytes, ctxt); + rc = ops->write( + dst.mem_seg, dst.mem_off, dst.val, dst.bytes, ctxt); if ( rc != 0 ) goto done; default: @@ -1011,50 +1004,51 @@ x86_emulate_memop( } switch ( b ) { + case 0xa0 ... 0xa1: /* mov moffs,{%al,%ax,%eax,%rax} */ + /* Source EA is not encoded via ModRM. */ + dst.type = OP_REG; + dst.reg = (unsigned long *)&_regs.eax; + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + if ( (rc = ops->read(ea_seg, _insn_fetch(ad_bytes), + &dst.val, dst.bytes, ctxt)) != 0 ) + goto done; + break; + case 0xa2 ... 0xa3: /* mov {%al,%ax,%eax,%rax},moffs */ + /* Destination EA is not encoded via ModRM. */ + dst.type = OP_MEM; + dst.mem_seg = ea_seg; + dst.mem_off = _insn_fetch(ad_bytes); + dst.bytes = (d & ByteOp) ? 1 : op_bytes; + dst.val = (unsigned long)_regs.eax; + break; case 0xa4 ... 0xa5: /* movs */ dst.type = OP_MEM; dst.bytes = (d & ByteOp) ? 1 : op_bytes; - if ( _regs.error_code & PFEC_write_access ) - { - /* Write fault: destination is special memory. */ - dst.ptr = (unsigned long *)cr2; - if ( (rc = ops->read_std(register_address(*seg, _regs.esi), - &dst.val, dst.bytes, ctxt)) != 0 ) - goto done; - ea = register_address(_regs.es, _regs.edi); - } - else - { - /* Read fault: source is special memory. */ - dst.ptr = (unsigned long *)register_address(_regs.es, _regs.edi); - if ( (rc = ops->read_emulated(cr2, &dst.val, - dst.bytes, ctxt)) != 0 ) - goto done; - ea = register_address(*seg, _regs.esi); - } - page_boundary_test(); + dst.mem_seg = X86_SEG_ES; + dst.mem_off = truncate_ea(_regs.edi); + if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi), + &dst.val, dst.bytes, ctxt)) != 0 ) + goto done; register_address_increment( _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes); register_address_increment( _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes); break; case 0xaa ... 0xab: /* stos */ - ea = register_address(_regs.es, _regs.edi); - page_boundary_test(); dst.type = OP_MEM; dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.ptr = (unsigned long *)cr2; + dst.mem_seg = X86_SEG_ES; + dst.mem_off = truncate_ea(_regs.edi); dst.val = _regs.eax; register_address_increment( _regs.edi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes); break; case 0xac ... 0xad: /* lods */ - ea = register_address(*seg, _regs.esi); - page_boundary_test(); dst.type = OP_REG; dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.ptr = (unsigned long *)&_regs.eax; - if ( (rc = ops->read_emulated(cr2, &dst.val, dst.bytes, ctxt)) != 0 ) + dst.reg = (unsigned long *)&_regs.eax; + if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi), + &dst.val, dst.bytes, ctxt)) != 0 ) goto done; register_address_increment( _regs.esi, (_regs.eflags & EFLG_DF) ? -dst.bytes : dst.bytes); @@ -1116,19 +1110,16 @@ x86_emulate_memop( { /* Failure: write the value we saw to EAX. */ dst.type = OP_REG; - dst.ptr = (unsigned long *)&_regs.eax; + dst.reg = (unsigned long *)&_regs.eax; } break; case 0xa3: bt: /* bt */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("bt", src, dst, _regs.eflags); break; case 0xb3: btr: /* btr */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("btr", src, dst, _regs.eflags); break; case 0xab: bts: /* bts */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags); break; case 0xb6 ... 0xb7: /* movzx */ @@ -1136,7 +1127,6 @@ x86_emulate_memop( dst.val = (d & ByteOp) ? (uint8_t)src.val : (uint16_t)src.val; break; case 0xbb: btc: /* btc */ - src.val &= (dst.bytes << 3) - 1; /* only subword offset */ emulate_2op_SrcV_nobyte("btc", src, dst, _regs.eflags); break; case 0xba: /* Grp8 */ @@ -1167,8 +1157,8 @@ x86_emulate_memop( #if defined(__i386__) { unsigned long old_lo, old_hi; - if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4, ctxt)) != 0) || - ((rc = ops->read_emulated(cr2+4, &old_hi, 4, ctxt)) != 0) ) + if ( ((rc = ops->read(ea_seg, ea_off+0, &old_lo, 4, ctxt)) != 0) || + ((rc = ops->read(ea_seg, ea_off+4, &old_hi, 4, ctxt)) != 0) ) goto done; if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) ) { @@ -1176,15 +1166,15 @@ x86_emulate_memop( _regs.edx = old_hi; _regs.eflags &= ~EFLG_ZF; } - else if ( ops->cmpxchg8b_emulated == NULL ) + else if ( ops->cmpxchg8b == NULL ) { rc = X86EMUL_UNHANDLEABLE; goto done; } else { - if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi, _regs.ebx, - _regs.ecx, ctxt)) != 0 ) + if ( (rc = ops->cmpxchg8b(ea_seg, ea_off, old_lo, old_hi, + _regs.ebx, _regs.ecx, ctxt)) != 0 ) goto done; _regs.eflags |= EFLG_ZF; } @@ -1193,7 +1183,7 @@ x86_emulate_memop( #elif defined(__x86_64__) { unsigned long old, new; - if ( (rc = ops->read_emulated(cr2, &old, 8, ctxt)) != 0 ) + if ( (rc = ops->read(ea_seg, ea_off, &old, 8, ctxt)) != 0 ) goto done; if ( ((uint32_t)(old>>0) != (uint32_t)_regs.eax) || ((uint32_t)(old>>32) != (uint32_t)_regs.edx) ) @@ -1205,7 +1195,7 @@ x86_emulate_memop( else { new = (_regs.ecx<<32)|(uint32_t)_regs.ebx; - if ( (rc = ops->cmpxchg_emulated(cr2, old, new, 8, ctxt)) != 0 ) + if ( (rc = ops->cmpxchg(ea_seg, ea_off, old, new, 8, ctxt)) != 0 ) goto done; _regs.eflags |= EFLG_ZF; } @@ -1219,55 +1209,4 @@ x86_emulate_memop( dprintf("Cannot emulate %02x\n", b); dump_instr(ctxt, ops); return -1; - - bad_ea: - dprintf("Access faulted on page boundary (cr2=%lx,ea=%lx).\n", cr2, ea); - dump_instr(ctxt, ops); - show_execution_state(ctxt->regs); - return -1; } - -#ifdef __XEN__ - -#include -#include - -int -x86_emulate_read_std( - unsigned long addr, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - unsigned int rc; - - *val = 0; - - if ( (rc = copy_from_user((void *)val, (void *)addr, bytes)) != 0 ) - { - propagate_page_fault(addr + bytes - rc, 0); /* read fault */ - return X86EMUL_PROPAGATE_FAULT; - } - - return X86EMUL_CONTINUE; -} - -int -x86_emulate_write_std( - unsigned long addr, - unsigned long val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - unsigned int rc; - - if ( (rc = copy_to_user((void *)addr, (void *)&val, bytes)) != 0 ) - { - propagate_page_fault(addr + bytes - rc, PFEC_write_access); - return X86EMUL_PROPAGATE_FAULT; - } - - return X86EMUL_CONTINUE; -} - -#endif diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h index 3bd912ce68..4bc49c5487 100644 --- a/xen/include/asm-x86/x86_emulate.h +++ b/xen/include/asm-x86/x86_emulate.h @@ -11,35 +11,27 @@ struct x86_emulate_ctxt; +#define X86_SEG_CS 0 +#define X86_SEG_SS 1 +#define X86_SEG_DS 2 +#define X86_SEG_ES 3 +#define X86_SEG_FS 4 +#define X86_SEG_GS 5 + /* * x86_emulate_ops: * * These operations represent the instruction emulator's interface to memory. - * There are two categories of operation: those that act on ordinary memory - * regions (*_std), and those that act on memory regions known to require - * special treatment or emulation (*_emulated). - * - * The emulator assumes that an instruction accesses only one 'emulated memory' - * location, that this location is the given linear faulting address (cr2), and - * that this is one of the instruction's data operands. Instruction fetches and - * stack operations are assumed never to access emulated memory. The emulator - * automatically deduces which operand of a string-move operation is accessing - * emulated memory, and assumes that the other operand accesses normal memory. * * NOTES: - * 1. The emulator isn't very smart about emulated vs. standard memory. - * 'Emulated memory' access addresses should be checked for sanity. - * 'Normal memory' accesses may fault, and the caller must arrange to - * detect and handle reentrancy into the emulator via recursive faults. - * Accesses may be unaligned and may cross page boundaries. - * 2. If the access fails (cannot emulate, or a standard access faults) then + * 1. If the access fails (cannot emulate, or a standard access faults) then * it is up to the memop to propagate the fault to the guest VM via * some out-of-band mechanism, unknown to the emulator. The memop signals * failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will * then immediately bail. - * 3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only + * 2. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only * cmpxchg8b_emulated need support 8-byte accesses. - * 4. The emulator cannot handle 64-bit mode emulation on an x86/32 system. + * 3. The emulator cannot handle 64-bit mode emulation on an x86/32 system. */ /* Access completed successfully: continue emulation as normal. */ #define X86EMUL_CONTINUE 0 @@ -52,74 +44,51 @@ struct x86_emulate_ctxt; struct x86_emulate_ops { /* - * read_std: Read bytes of standard (non-emulated/special) memory. - * Used for instruction fetch, stack operations, and others. - * @addr: [IN ] Linear address from which to read. - * @val: [OUT] Value read from memory, zero-extended to 'u_long'. + * All functions: + * @seg: [IN ] Segment being dereferenced (specified as X86_SEG_??). + * @offset [IN ] Offset within segment. + */ + + /* + * read: Emulate a memory read. + * @val: [OUT] Value read from memory, zero-extended to 'ulong'. * @bytes: [IN ] Number of bytes to read from memory. */ - int (*read_std)( - unsigned long addr, + int (*read)( + unsigned int seg, + unsigned long offset, unsigned long *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt); /* - * write_std: Write bytes of standard (non-emulated/special) memory. - * Used for stack operations, and others. - * @addr: [IN ] Linear address to which to write. + * write: Emulate a memory write. * @val: [IN ] Value to write to memory (low-order bytes used as req'd). * @bytes: [IN ] Number of bytes to write to memory. */ - int (*write_std)( - unsigned long addr, + int (*write)( + unsigned int seg, + unsigned long offset, unsigned long val, unsigned int bytes, struct x86_emulate_ctxt *ctxt); /* - * read_emulated: Read bytes from emulated/special memory area. - * @addr: [IN ] Linear address from which to read. - * @val: [OUT] Value read from memory, zero-extended to 'u_long'. - * @bytes: [IN ] Number of bytes to read from memory. - */ - int (*read_emulated)( - unsigned long addr, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt); - - /* - * write_emulated: Read bytes from emulated/special memory area. - * @addr: [IN ] Linear address to which to write. - * @val: [IN ] Value to write to memory (low-order bytes used as req'd). - * @bytes: [IN ] Number of bytes to write to memory. - */ - int (*write_emulated)( - unsigned long addr, - unsigned long val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt); - - /* - * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an - * emulated/special memory area. - * @addr: [IN ] Linear address to access. + * cmpxchg: Emulate an atomic (LOCKed) CMPXCHG operation. * @old: [IN ] Value expected to be current at @addr. * @new: [IN ] Value to write to @addr. * @bytes: [IN ] Number of bytes to access using CMPXCHG. */ - int (*cmpxchg_emulated)( - unsigned long addr, + int (*cmpxchg)( + unsigned int seg, + unsigned long offset, unsigned long old, unsigned long new, unsigned int bytes, struct x86_emulate_ctxt *ctxt); /* - * cmpxchg8b_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an - * emulated/special memory area. - * @addr: [IN ] Linear address to access. + * cmpxchg8b: Emulate an atomic (LOCKed) CMPXCHG8B operation. * @old: [IN ] Value expected to be current at @addr. * @new: [IN ] Value to write to @addr. * NOTES: @@ -128,8 +97,9 @@ struct x86_emulate_ops * 2. Not defining this function (i.e., specifying NULL) is equivalent * to defining a function that always returns X86EMUL_UNHANDLEABLE. */ - int (*cmpxchg8b_emulated)( - unsigned long addr, + int (*cmpxchg8b)( + unsigned int seg, + unsigned long offset, unsigned long old_lo, unsigned long old_hi, unsigned long new_lo, @@ -137,20 +107,6 @@ struct x86_emulate_ops struct x86_emulate_ctxt *ctxt); }; -/* Standard reader/writer functions that callers may wish to use. */ -extern int -x86_emulate_read_std( - unsigned long addr, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt); -extern int -x86_emulate_write_std( - unsigned long addr, - unsigned long val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt); - struct cpu_user_regs; struct x86_emulate_ctxt @@ -158,9 +114,6 @@ struct x86_emulate_ctxt /* Register state before/after emulation. */ struct cpu_user_regs *regs; - /* Linear faulting address (if emulating a page-faulting instruction). */ - unsigned long cr2; - /* Emulated execution mode, represented by an X86EMUL_MODE value. */ int mode; }; From a173b7d011523df95259a206a5ff5d6ceeea336b Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:38:50 +0000 Subject: [PATCH 069/282] [XEN] Kexec / Kdump: Generic code This patch implements the generic portion of the Kexec / Kdump port to Xen. Signed-Off-By: Magnus Damm Signed-Off-By: Simon Horman --- .../drivers/xen/core/Makefile | 1 + .../drivers/xen/core/machine_kexec.c | 170 ++++++++ patches/linux-2.6.16.33/kexec-generic.patch | 228 +++++++++++ patches/linux-2.6.16.33/series | 1 + xen/arch/ia64/xen/Makefile | 2 + xen/arch/ia64/xen/crash.c | 19 + xen/arch/ia64/xen/machine_kexec.c | 34 ++ xen/arch/powerpc/Makefile | 2 + xen/arch/powerpc/crash.c | 19 + xen/arch/powerpc/machine_kexec.c | 34 ++ xen/arch/x86/Makefile | 2 + xen/arch/x86/crash.c | 19 + xen/arch/x86/machine_kexec.c | 34 ++ xen/common/Makefile | 1 + xen/common/kexec.c | 370 ++++++++++++++++++ xen/common/page_alloc.c | 35 +- xen/drivers/char/console.c | 3 + xen/include/asm-ia64/elf.h | 30 ++ xen/include/asm-ia64/kexec.h | 25 ++ xen/include/asm-powerpc/elf.h | 30 ++ xen/include/asm-powerpc/kexec.h | 25 ++ xen/include/asm-x86/elf.h | 30 ++ xen/include/asm-x86/kexec.h | 24 ++ xen/include/public/elfnote.h | 19 + xen/include/public/kexec.h | 131 +++++++ xen/include/xen/elf.h | 16 +- xen/include/xen/elfcore.h | 137 +++++++ xen/include/xen/hypercall.h | 6 + xen/include/xen/kexec.h | 43 ++ xen/include/xen/mm.h | 1 + 30 files changed, 1467 insertions(+), 24 deletions(-) create mode 100644 linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c create mode 100644 patches/linux-2.6.16.33/kexec-generic.patch create mode 100644 xen/arch/ia64/xen/crash.c create mode 100644 xen/arch/ia64/xen/machine_kexec.c create mode 100644 xen/arch/powerpc/crash.c create mode 100644 xen/arch/powerpc/machine_kexec.c create mode 100644 xen/arch/x86/crash.c create mode 100644 xen/arch/x86/machine_kexec.c create mode 100644 xen/common/kexec.c create mode 100644 xen/include/asm-ia64/elf.h create mode 100644 xen/include/asm-ia64/kexec.h create mode 100644 xen/include/asm-powerpc/elf.h create mode 100644 xen/include/asm-powerpc/kexec.h create mode 100644 xen/include/asm-x86/elf.h create mode 100644 xen/include/asm-x86/kexec.h create mode 100644 xen/include/public/kexec.h create mode 100644 xen/include/xen/elfcore.h create mode 100644 xen/include/xen/kexec.h diff --git a/linux-2.6-xen-sparse/drivers/xen/core/Makefile b/linux-2.6-xen-sparse/drivers/xen/core/Makefile index 6154454339..519ea37351 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/Makefile +++ b/linux-2.6-xen-sparse/drivers/xen/core/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_XEN_SYSFS) += xen_sysfs.o obj-$(CONFIG_XEN_SKBUFF) += skbuff.o obj-$(CONFIG_XEN_REBOOT) += reboot.o machine_reboot.o obj-$(CONFIG_XEN_SMPBOOT) += smpboot.o +obj-$(CONFIG_KEXEC) += machine_kexec.o diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c new file mode 100644 index 0000000000..08820ad37d --- /dev/null +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -0,0 +1,170 @@ +/* + * drivers/xen/core/machine_kexec.c + * handle transition of Linux booting another kernel + */ + +#include +#include +#include +#include +#include + +extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, + struct kimage *image); + +int xen_max_nr_phys_cpus; +struct resource xen_hypervisor_res; +struct resource *xen_phys_cpus; + +void xen_machine_kexec_setup_resources(void) +{ + xen_kexec_range_t range; + struct resource *res; + int k = 0; + + /* determine maximum number of physical cpus */ + + while (1) { + memset(&range, 0, sizeof(range)); + range.range = KEXEC_RANGE_MA_CPU; + range.nr = k; + + if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) + break; + + k++; + } + + xen_max_nr_phys_cpus = k; + + /* allocate xen_phys_cpus */ + + xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource)); + BUG_ON(!xen_phys_cpus); + + /* fill in xen_phys_cpus with per-cpu crash note information */ + + for (k = 0; k < xen_max_nr_phys_cpus; k++) { + memset(&range, 0, sizeof(range)); + range.range = KEXEC_RANGE_MA_CPU; + range.nr = k; + + BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)); + + res = xen_phys_cpus + k; + + memset(res, 0, sizeof(*res)); + res->name = "Crash note"; + res->start = range.start; + res->end = range.start + range.size - 1; + res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + } + + /* fill in xen_hypervisor_res with hypervisor machine address range */ + + memset(&range, 0, sizeof(range)); + range.range = KEXEC_RANGE_MA_XEN; + + BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)); + + xen_hypervisor_res.name = "Hypervisor code and data"; + xen_hypervisor_res.start = range.start; + xen_hypervisor_res.end = range.start + range.size - 1; + xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM; + + /* fill in crashk_res if range is reserved by hypervisor */ + + memset(&range, 0, sizeof(range)); + range.range = KEXEC_RANGE_MA_CRASH; + + BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)); + + if (range.size) { + crashk_res.start = range.start; + crashk_res.end = range.start + range.size - 1; + } +} + +void xen_machine_kexec_register_resources(struct resource *res) +{ + int k; + + request_resource(res, &xen_hypervisor_res); + + for (k = 0; k < xen_max_nr_phys_cpus; k++) + request_resource(res, xen_phys_cpus + k); + +} + +static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) +{ + machine_kexec_setup_load_arg(xki, image); + + xki->indirection_page = image->head; + xki->start_address = image->start; +} + +/* + * Load the image into xen so xen can kdump itself + * This might have been done in prepare, but prepare + * is currently called too early. It might make sense + * to move prepare, but for now, just add an extra hook. + */ +int xen_machine_kexec_load(struct kimage *image) +{ + xen_kexec_load_t xkl; + + memset(&xkl, 0, sizeof(xkl)); + xkl.type = image->type; + setup_load_arg(&xkl.image, image); + return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl); +} + +/* + * Unload the image that was stored by machine_kexec_load() + * This might have been done in machine_kexec_cleanup() but it + * is called too late, and its possible xen could try and kdump + * using resources that have been freed. + */ +void xen_machine_kexec_unload(struct kimage *image) +{ + xen_kexec_load_t xkl; + + memset(&xkl, 0, sizeof(xkl)); + xkl.type = image->type; + HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl); +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + * + * This has the hypervisor move to the prefered reboot CPU, + * stop all CPUs and kexec. That is it combines machine_shutdown() + * and machine_kexec() in Linux kexec terms. + */ +NORET_TYPE void xen_machine_kexec(struct kimage *image) +{ + xen_kexec_exec_t xke; + + memset(&xke, 0, sizeof(xke)); + xke.type = image->type; + HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke); + panic("KEXEC_CMD_kexec hypercall should not return\n"); +} + +void machine_shutdown(void) +{ + /* do nothing */ +} + + +/* + * Local variables: + * c-file-style: "linux" + * indent-tabs-mode: t + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/patches/linux-2.6.16.33/kexec-generic.patch b/patches/linux-2.6.16.33/kexec-generic.patch new file mode 100644 index 0000000000..2e01a7aab0 --- /dev/null +++ b/patches/linux-2.6.16.33/kexec-generic.patch @@ -0,0 +1,228 @@ +--- 0001/include/linux/kexec.h ++++ work/include/linux/kexec.h +@@ -31,6 +31,13 @@ + #error KEXEC_ARCH not defined + #endif + ++#ifndef KEXEC_ARCH_HAS_PAGE_MACROS ++#define kexec_page_to_pfn(page) page_to_pfn(page) ++#define kexec_pfn_to_page(pfn) pfn_to_page(pfn) ++#define kexec_virt_to_phys(addr) virt_to_phys(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(addr) ++#endif ++ + /* + * This structure is used to hold the arguments that are used when loading + * kernel binaries. +@@ -91,6 +98,13 @@ struct kimage { + extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; + extern int machine_kexec_prepare(struct kimage *image); + extern void machine_kexec_cleanup(struct kimage *image); ++#ifdef CONFIG_XEN ++extern int xen_machine_kexec_load(struct kimage *image); ++extern void xen_machine_kexec_unload(struct kimage *image); ++extern NORET_TYPE void xen_machine_kexec(struct kimage *image) ATTRIB_NORET; ++extern void xen_machine_kexec_setup_resources(void); ++extern void xen_machine_kexec_register_resources(struct resource *res); ++#endif + extern asmlinkage long sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments, +--- 0001/kernel/kexec.c ++++ work/kernel/kexec.c +@@ -403,7 +403,7 @@ static struct page *kimage_alloc_normal_ + pages = kimage_alloc_pages(GFP_KERNEL, order); + if (!pages) + break; +- pfn = page_to_pfn(pages); ++ pfn = kexec_page_to_pfn(pages); + epfn = pfn + count; + addr = pfn << PAGE_SHIFT; + eaddr = epfn << PAGE_SHIFT; +@@ -437,6 +437,7 @@ static struct page *kimage_alloc_normal_ + return pages; + } + ++#ifndef CONFIG_XEN + static struct page *kimage_alloc_crash_control_pages(struct kimage *image, + unsigned int order) + { +@@ -490,7 +491,7 @@ static struct page *kimage_alloc_crash_c + } + /* If I don't overlap any segments I have found my hole! */ + if (i == image->nr_segments) { +- pages = pfn_to_page(hole_start >> PAGE_SHIFT); ++ pages = kexec_pfn_to_page(hole_start >> PAGE_SHIFT); + break; + } + } +@@ -517,6 +518,13 @@ struct page *kimage_alloc_control_pages( + + return pages; + } ++#else /* !CONFIG_XEN */ ++struct page *kimage_alloc_control_pages(struct kimage *image, ++ unsigned int order) ++{ ++ return kimage_alloc_normal_control_pages(image, order); ++} ++#endif + + static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) + { +@@ -532,7 +540,7 @@ static int kimage_add_entry(struct kimag + return -ENOMEM; + + ind_page = page_address(page); +- *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; ++ *image->entry = kexec_virt_to_phys(ind_page) | IND_INDIRECTION; + image->entry = ind_page; + image->last_entry = ind_page + + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); +@@ -593,13 +601,13 @@ static int kimage_terminate(struct kimag + #define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION)? \ +- phys_to_virt((entry & PAGE_MASK)): ptr +1) ++ kexec_phys_to_virt((entry & PAGE_MASK)): ptr +1) + + static void kimage_free_entry(kimage_entry_t entry) + { + struct page *page; + +- page = pfn_to_page(entry >> PAGE_SHIFT); ++ page = kexec_pfn_to_page(entry >> PAGE_SHIFT); + kimage_free_pages(page); + } + +@@ -611,6 +619,10 @@ static void kimage_free(struct kimage *i + if (!image) + return; + ++#ifdef CONFIG_XEN ++ xen_machine_kexec_unload(image); ++#endif ++ + kimage_free_extra_pages(image); + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_INDIRECTION) { +@@ -686,7 +698,7 @@ static struct page *kimage_alloc_page(st + * have a match. + */ + list_for_each_entry(page, &image->dest_pages, lru) { +- addr = page_to_pfn(page) << PAGE_SHIFT; ++ addr = kexec_page_to_pfn(page) << PAGE_SHIFT; + if (addr == destination) { + list_del(&page->lru); + return page; +@@ -701,12 +713,12 @@ static struct page *kimage_alloc_page(st + if (!page) + return NULL; + /* If the page cannot be used file it away */ +- if (page_to_pfn(page) > ++ if (kexec_page_to_pfn(page) > + (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { + list_add(&page->lru, &image->unuseable_pages); + continue; + } +- addr = page_to_pfn(page) << PAGE_SHIFT; ++ addr = kexec_page_to_pfn(page) << PAGE_SHIFT; + + /* If it is the destination page we want use it */ + if (addr == destination) +@@ -729,7 +741,7 @@ static struct page *kimage_alloc_page(st + struct page *old_page; + + old_addr = *old & PAGE_MASK; +- old_page = pfn_to_page(old_addr >> PAGE_SHIFT); ++ old_page = kexec_pfn_to_page(old_addr >> PAGE_SHIFT); + copy_highpage(page, old_page); + *old = addr | (*old & ~PAGE_MASK); + +@@ -779,7 +791,7 @@ static int kimage_load_normal_segment(st + result = -ENOMEM; + goto out; + } +- result = kimage_add_page(image, page_to_pfn(page) ++ result = kimage_add_page(image, kexec_page_to_pfn(page) + << PAGE_SHIFT); + if (result < 0) + goto out; +@@ -811,6 +823,7 @@ out: + return result; + } + ++#ifndef CONFIG_XEN + static int kimage_load_crash_segment(struct kimage *image, + struct kexec_segment *segment) + { +@@ -833,7 +846,7 @@ static int kimage_load_crash_segment(str + char *ptr; + size_t uchunk, mchunk; + +- page = pfn_to_page(maddr >> PAGE_SHIFT); ++ page = kexec_pfn_to_page(maddr >> PAGE_SHIFT); + if (page == 0) { + result = -ENOMEM; + goto out; +@@ -881,6 +894,13 @@ static int kimage_load_segment(struct ki + + return result; + } ++#else /* CONFIG_XEN */ ++static int kimage_load_segment(struct kimage *image, ++ struct kexec_segment *segment) ++{ ++ return kimage_load_normal_segment(image, segment); ++} ++#endif + + /* + * Exec Kernel system call: for obvious reasons only root may call it. +@@ -991,6 +1011,11 @@ asmlinkage long sys_kexec_load(unsigned + if (result) + goto out; + } ++#ifdef CONFIG_XEN ++ result = xen_machine_kexec_load(image); ++ if (result) ++ goto out; ++#endif + /* Install the new kernel, and Uninstall the old */ + image = xchg(dest_image, image); + +@@ -1045,7 +1070,6 @@ void crash_kexec(struct pt_regs *regs) + struct kimage *image; + int locked; + +- + /* Take the kexec_lock here to prevent sys_kexec_load + * running on one cpu from replacing the crash kernel + * we are using after a panic on a different cpu. +@@ -1061,7 +1085,11 @@ void crash_kexec(struct pt_regs *regs) + struct pt_regs fixed_regs; + crash_setup_regs(&fixed_regs, regs); + machine_crash_shutdown(&fixed_regs); ++#ifdef CONFIG_XEN ++ xen_machine_kexec(image); ++#else + machine_kexec(image); ++#endif + } + xchg(&kexec_lock, 0); + } +--- 0002/kernel/sys.c ++++ work/kernel/sys.c +@@ -435,8 +435,12 @@ void kernel_kexec(void) + kernel_restart_prepare(NULL); + printk(KERN_EMERG "Starting new kernel\n"); + machine_shutdown(); ++#ifdef CONFIG_XEN ++ xen_machine_kexec(image); ++#else + machine_kexec(image); + #endif ++#endif + } + EXPORT_SYMBOL_GPL(kernel_kexec); + diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index ef2c35842e..8d3ec1a0df 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -1,3 +1,4 @@ +kexec-generic.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch diff --git a/xen/arch/ia64/xen/Makefile b/xen/arch/ia64/xen/Makefile index 87f22f0966..c50c47dde9 100644 --- a/xen/arch/ia64/xen/Makefile +++ b/xen/arch/ia64/xen/Makefile @@ -1,3 +1,5 @@ +obj-y += machine_kexec.o +obj-y += crash.o obj-y += acpi.o obj-y += dom0_ops.o obj-y += domain.o diff --git a/xen/arch/ia64/xen/crash.c b/xen/arch/ia64/xen/crash.c new file mode 100644 index 0000000000..f1729786ea --- /dev/null +++ b/xen/arch/ia64/xen/crash.c @@ -0,0 +1,19 @@ +#include /* for printk() used in stub */ +#include +#include + +void machine_crash_shutdown(void) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/arch/ia64/xen/machine_kexec.c b/xen/arch/ia64/xen/machine_kexec.c new file mode 100644 index 0000000000..639f845ac1 --- /dev/null +++ b/xen/arch/ia64/xen/machine_kexec.c @@ -0,0 +1,34 @@ +#include /* for printk() used in stubs */ +#include +#include + +int machine_kexec_load(int type, int slot, xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + return -1; +} + +void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +void machine_shutdown(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/powerpc/Makefile b/xen/arch/powerpc/Makefile index 5db65c2c7c..a386534069 100644 --- a/xen/arch/powerpc/Makefile +++ b/xen/arch/powerpc/Makefile @@ -40,6 +40,8 @@ obj-y += smp-tbsync.o obj-y += sysctl.o obj-y += time.o obj-y += usercopy.o +obj-y += machine_kexec.o +obj-y += crash.o obj-$(debug) += 0opt.o obj-$(crash_debug) += gdbstub.o diff --git a/xen/arch/powerpc/crash.c b/xen/arch/powerpc/crash.c new file mode 100644 index 0000000000..f1729786ea --- /dev/null +++ b/xen/arch/powerpc/crash.c @@ -0,0 +1,19 @@ +#include /* for printk() used in stub */ +#include +#include + +void machine_crash_shutdown(void) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/arch/powerpc/machine_kexec.c b/xen/arch/powerpc/machine_kexec.c new file mode 100644 index 0000000000..639f845ac1 --- /dev/null +++ b/xen/arch/powerpc/machine_kexec.c @@ -0,0 +1,34 @@ +#include /* for printk() used in stubs */ +#include +#include + +int machine_kexec_load(int type, int slot, xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + return -1; +} + +void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +void machine_shutdown(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 89cc508d02..c8cb3af177 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -43,6 +43,8 @@ obj-y += trampoline.o obj-y += traps.o obj-y += usercopy.o obj-y += x86_emulate.o +obj-y += machine_kexec.o +obj-y += crash.o obj-$(crash_debug) += gdbstub.o diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c new file mode 100644 index 0000000000..f1729786ea --- /dev/null +++ b/xen/arch/x86/crash.c @@ -0,0 +1,19 @@ +#include /* for printk() used in stub */ +#include +#include + +void machine_crash_shutdown(void) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/arch/x86/machine_kexec.c b/xen/arch/x86/machine_kexec.c new file mode 100644 index 0000000000..639f845ac1 --- /dev/null +++ b/xen/arch/x86/machine_kexec.c @@ -0,0 +1,34 @@ +#include /* for printk() used in stubs */ +#include +#include + +int machine_kexec_load(int type, int slot, xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + return -1; +} + +void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +void machine_shutdown(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/Makefile b/xen/common/Makefile index 770c4b376f..966e80d54a 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -7,6 +7,7 @@ obj-y += event_channel.o obj-y += grant_table.o obj-y += kernel.o obj-y += keyhandler.o +obj-y += kexec.o obj-y += lib.o obj-y += memory.o obj-y += multicall.o diff --git a/xen/common/kexec.c b/xen/common/kexec.c new file mode 100644 index 0000000000..04fe8ef67f --- /dev/null +++ b/xen/common/kexec.c @@ -0,0 +1,370 @@ +/****************************************************************************** + * kexec.c - Achitecture independent kexec code for Xen + * + * Xen port written by: + * - Simon 'Horms' Horman + * - Magnus Damm + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char opt_crashkernel[32] = ""; +string_param("crashkernel", opt_crashkernel); + +DEFINE_PER_CPU (crash_note_t, crash_notes); +cpumask_t crash_saved_cpus; +int crashing_cpu; + +xen_kexec_image_t kexec_image[KEXEC_IMAGE_NR]; + +#define KEXEC_FLAG_DEFAULT_POS (KEXEC_IMAGE_NR + 0) +#define KEXEC_FLAG_CRASH_POS (KEXEC_IMAGE_NR + 1) +#define KEXEC_FLAG_IN_PROGRESS (KEXEC_IMAGE_NR + 2) + +unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */ + +spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED; + +static void one_cpu_only(void) +{ + /* Only allow the first cpu to continue - force other cpus to spin */ + if (test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) + { + while (1); + } +} + +/* Save the registers in the per-cpu crash note buffer */ + +void machine_crash_save_cpu(void) +{ + int cpu = smp_processor_id(); + crash_note_t *cntp; + + if (!cpu_test_and_set(cpu, crash_saved_cpus)) + { + cntp = &per_cpu(crash_notes, cpu); + elf_core_save_regs(&cntp->core.desc.desc.pr_reg, + &cntp->xen_regs.desc.desc); + + /* setup crash "CORE" note */ + setup_crash_note(cntp, core, CORE_STR, CORE_STR_LEN, NT_PRSTATUS); + + /* setup crash note "Xen", XEN_ELFNOTE_CRASH_REGS */ + setup_crash_note(cntp, xen_regs, XEN_STR, XEN_STR_LEN, + XEN_ELFNOTE_CRASH_REGS); + } +} + +/* Setup the single Xen specific info crash note */ + +crash_xen_info_t *machine_crash_save_info(void) +{ + int cpu = smp_processor_id(); + crash_note_t *cntp; + crash_xen_info_t *info; + + BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus)); + + cntp = &per_cpu(crash_notes, cpu); + + /* setup crash note "Xen", XEN_ELFNOTE_CRASH_INFO */ + setup_crash_note(cntp, xen_info, XEN_STR, XEN_STR_LEN, + XEN_ELFNOTE_CRASH_INFO); + + info = &cntp->xen_info.desc.desc; + + info->xen_major_version = xen_major_version(); + info->xen_minor_version = xen_minor_version(); + info->xen_extra_version = __pa(xen_extra_version()); + info->xen_changeset = __pa(xen_changeset()); + info->xen_compiler = __pa(xen_compiler()); + info->xen_compile_date = __pa(xen_compile_date()); + info->xen_compile_time = __pa(xen_compile_time()); + info->tainted = tainted; + + return info; +} + +void machine_crash_kexec(void) +{ + int pos; + xen_kexec_image_t *image; + + one_cpu_only(); + + machine_crash_save_cpu(); + crashing_cpu = smp_processor_id(); + + machine_crash_shutdown(); + + pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0); + + if (test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags)) + { + image = &kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]; + machine_kexec(image); /* Does not return */ + } + + while (1); /* No image available - just spin */ +} + +static void do_crashdump_trigger(unsigned char key) +{ + printk("triggering crashdump\n"); + machine_crash_kexec(); +} + +static __init int register_crashdump_trigger(void) +{ + register_keyhandler('c', do_crashdump_trigger, "trigger a crashdump"); + return 0; +} +__initcall(register_crashdump_trigger); + +void machine_kexec_reserved(xen_kexec_reserve_t *reservation) +{ + unsigned long val[2]; + char *str = opt_crashkernel; + int k = 0; + + memset(reservation, 0, sizeof(*reservation)); + + while (k < ARRAY_SIZE(val)) { + if (*str == '\0') { + break; + } + val[k] = simple_strtoul(str, &str, 0); + switch (toupper(*str)) { + case 'G': val[k] <<= 10; + case 'M': val[k] <<= 10; + case 'K': val[k] <<= 10; + str++; + } + if (*str == '@') { + str++; + } + k++; + } + + if (k == ARRAY_SIZE(val)) { + reservation->size = val[0]; + reservation->start = val[1]; + } +} + +static int kexec_get_reserve(xen_kexec_range_t *range) +{ + xen_kexec_reserve_t reservation; + + machine_kexec_reserved(&reservation); + + range->start = reservation.start; + range->size = reservation.size; + return 0; +} + +extern unsigned long _text, _end; + +static int kexec_get_xen(xen_kexec_range_t *range, int get_ma) +{ + if (get_ma) + range->start = virt_to_maddr(&_text); + else + range->start = (unsigned long) &_text; + + range->size = &_end - &_text; + return 0; +} + +static int kexec_get_cpu(xen_kexec_range_t *range) +{ + if (range->nr < 0 || range->nr >= num_present_cpus()) + return -EINVAL; + + range->start = __pa((unsigned long)&per_cpu(crash_notes, range->nr)); + range->size = sizeof(crash_note_t); + return 0; +} + +static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_range_t range; + int ret = -EINVAL; + + if (unlikely(copy_from_guest(&range, uarg, 1))) + return -EFAULT; + + switch (range.range) + { + case KEXEC_RANGE_MA_CRASH: + ret = kexec_get_reserve(&range); + break; + case KEXEC_RANGE_MA_XEN: + ret = kexec_get_xen(&range, 1); + break; + case KEXEC_RANGE_VA_XEN: + ret = kexec_get_xen(&range, 0); + break; + case KEXEC_RANGE_MA_CPU: + ret = kexec_get_cpu(&range); + break; + } + + if (ret == 0 && unlikely(copy_to_guest(uarg, &range, 1))) + return -EFAULT; + + return ret; +} + +static int kexec_load_get_bits(int type, int *base, int *bit) +{ + switch (type) + { + case KEXEC_TYPE_DEFAULT: + *base = KEXEC_IMAGE_DEFAULT_BASE; + *bit = KEXEC_FLAG_DEFAULT_POS; + break; + case KEXEC_TYPE_CRASH: + *base = KEXEC_IMAGE_CRASH_BASE; + *bit = KEXEC_FLAG_CRASH_POS; + break; + default: + return -1; + } + return 0; +} + +static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_load_t load; + xen_kexec_image_t *image; + int base, bit, pos; + int ret = 0; + + if (unlikely(copy_from_guest(&load, uarg, 1))) + return -EFAULT; + + if (kexec_load_get_bits(load.type, &base, &bit)) + return -EINVAL; + + pos = (test_bit(bit, &kexec_flags) != 0); + + /* Load the user data into an unused image */ + if (op == KEXEC_CMD_kexec_load) + { + image = &kexec_image[base + !pos]; + + BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */ + + memcpy(image, &load.image, sizeof(*image)); + + if (!(ret = machine_kexec_load(load.type, base + !pos, image))) + { + /* Set image present bit */ + set_bit((base + !pos), &kexec_flags); + + /* Make new image the active one */ + change_bit(bit, &kexec_flags); + } + } + + /* Unload the old image if present and load successful */ + if (ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) + { + if (test_and_clear_bit((base + pos), &kexec_flags)) + { + image = &kexec_image[base + pos]; + machine_kexec_unload(load.type, base + pos, image); + } + } + + return ret; +} + +static int kexec_exec(XEN_GUEST_HANDLE(void) uarg) +{ + xen_kexec_exec_t exec; + xen_kexec_image_t *image; + int base, bit, pos; + + if (unlikely(copy_from_guest(&exec, uarg, 1))) + return -EFAULT; + + if (kexec_load_get_bits(exec.type, &base, &bit)) + return -EINVAL; + + pos = (test_bit(bit, &kexec_flags) != 0); + + /* Only allow kexec/kdump into loaded images */ + if (!test_bit(base + pos, &kexec_flags)) + return -ENOENT; + + switch (exec.type) + { + case KEXEC_TYPE_DEFAULT: + image = &kexec_image[base + pos]; + one_cpu_only(); + machine_shutdown(image); /* Does not return */ + break; + case KEXEC_TYPE_CRASH: + machine_crash_kexec(); /* Does not return */ + break; + } + + return -EINVAL; /* never reached */ +} + +long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) +{ + unsigned long flags; + int ret = -EINVAL; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + switch (op) + { + case KEXEC_CMD_kexec_get_range: + ret = kexec_get_range(uarg); + break; + case KEXEC_CMD_kexec_load: + case KEXEC_CMD_kexec_unload: + spin_lock_irqsave(&kexec_lock, flags); + if (!test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) + { + ret = kexec_load_unload(op, uarg); + } + spin_unlock_irqrestore(&kexec_lock, flags); + break; + case KEXEC_CMD_kexec: + ret = kexec_exec(uarg); + break; + } + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 2e79ce4188..1697226e90 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -237,26 +237,37 @@ void init_boot_pages(paddr_t ps, paddr_t pe) } } -unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align) +unsigned long alloc_boot_pages_at(unsigned long nr_pfns, unsigned long pfn_at) { - unsigned long pg, i; + unsigned long i; - for ( pg = 0; (pg + nr_pfns) < max_page; pg += pfn_align ) + for ( i = 0; i < nr_pfns; i++ ) + if ( allocated_in_map(pfn_at + i) ) + break; + + if ( i == nr_pfns ) { - for ( i = 0; i < nr_pfns; i++ ) - if ( allocated_in_map(pg + i) ) - break; - - if ( i == nr_pfns ) - { - map_alloc(pg, nr_pfns); - return pg; - } + map_alloc(pfn_at, nr_pfns); + return pfn_at; } return 0; } +unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align) +{ + unsigned long pg, i = 0; + + for ( pg = 0; (pg + nr_pfns) < max_page; pg += pfn_align ) + { + i = alloc_boot_pages_at(nr_pfns, pg); + if (i != 0) + break; + } + + return i; +} + /************************* diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 6a97fc2965..1bca60cc80 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -865,6 +866,8 @@ void panic(const char *fmt, ...) debugger_trap_immediate(); + machine_crash_kexec(); + if ( opt_noreboot ) { machine_halt(); diff --git a/xen/include/asm-ia64/elf.h b/xen/include/asm-ia64/elf.h new file mode 100644 index 0000000000..fbd92bf4cd --- /dev/null +++ b/xen/include/asm-ia64/elf.h @@ -0,0 +1,30 @@ +#ifndef __IA64_ELF_H__ +#define __IA64_ELF_H__ + +#include /* for printk() used in stub */ + +typedef struct { + unsigned long dummy; +} ELF_Gregset; + +typedef struct { + unsigned long dummy; +} crash_xen_core_t; + +extern inline void elf_core_save_regs(ELF_Gregset *core_regs, + crash_xen_core_t *xen_core_regs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __IA64_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-ia64/kexec.h b/xen/include/asm-ia64/kexec.h new file mode 100644 index 0000000000..45756e8f64 --- /dev/null +++ b/xen/include/asm-ia64/kexec.h @@ -0,0 +1,25 @@ +#ifndef __IA64_KEXEC_H__ +#define __IA64_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include +#include + +static inline void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __IA64_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/include/asm-powerpc/elf.h b/xen/include/asm-powerpc/elf.h new file mode 100644 index 0000000000..24fc958387 --- /dev/null +++ b/xen/include/asm-powerpc/elf.h @@ -0,0 +1,30 @@ +#ifndef _ASM_ELF_H__ +#define _ASM_ELF_H__ + +#include /* for printk() used in stub */ + +typedef struct { + unsigned long dummy; +} ELF_Gregset; + +typedef struct { + unsigned long dummy; +} crash_xen_core_t; + +extern inline void elf_core_save_regs(ELF_Gregset *core_regs, + crash_xen_core_t *xen_core_regs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* _ASM_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-powerpc/kexec.h b/xen/include/asm-powerpc/kexec.h new file mode 100644 index 0000000000..f228972047 --- /dev/null +++ b/xen/include/asm-powerpc/kexec.h @@ -0,0 +1,25 @@ +#ifndef _ASM_KEXEC_H__ +#define _ASM_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include +#include + +static inline void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* _ASM_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/xen/include/asm-x86/elf.h b/xen/include/asm-x86/elf.h new file mode 100644 index 0000000000..bfd7913d10 --- /dev/null +++ b/xen/include/asm-x86/elf.h @@ -0,0 +1,30 @@ +#ifndef __X86_ELF_H__ +#define __X86_ELF_H__ + +#include /* for printk() used in stub */ + +typedef struct { + unsigned long dummy; +} ELF_Gregset; + +typedef struct { + unsigned long dummy; +} crash_xen_core_t; + +extern inline void elf_core_save_regs(ELF_Gregset *core_regs, + crash_xen_core_t *xen_core_regs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __X86_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-x86/kexec.h b/xen/include/asm-x86/kexec.h new file mode 100644 index 0000000000..ba47dbf6dc --- /dev/null +++ b/xen/include/asm-x86/kexec.h @@ -0,0 +1,24 @@ +#ifndef __X86_KEXEC_H__ +#define __X86_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include +#include + +static inline void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __X86_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/elfnote.h b/xen/include/public/elfnote.h index ccf959d6e1..4924767d30 100644 --- a/xen/include/public/elfnote.h +++ b/xen/include/public/elfnote.h @@ -147,6 +147,25 @@ */ #define XEN_ELFNOTE_HV_START_LOW 12 +/* + * System information exported through crash notes. + * + * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO + * note in case of a system crash. This note will contain various + * information about the system, see xen/include/xen/elfcore.h. + */ +#define XEN_ELFNOTE_CRASH_INFO 0x1000001 + +/* + * System registers exported through crash notes. + * + * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS + * note per cpu in case of a system crash. This note is architecture + * specific and will contain registers not saved in the "CORE" note. + * See xen/include/xen/elfcore.h for more information. + */ +#define XEN_ELFNOTE_CRASH_REGS 0x1000002 + #endif /* __XEN_PUBLIC_ELFNOTE_H__ */ /* diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h new file mode 100644 index 0000000000..c51f24ccdd --- /dev/null +++ b/xen/include/public/kexec.h @@ -0,0 +1,131 @@ +/****************************************************************************** + * kexec.h - Public portion + * + * Xen port written by: + * - Simon 'Horms' Horman + * - Magnus Damm + */ + +#ifndef _XEN_PUBLIC_KEXEC_H +#define _XEN_PUBLIC_KEXEC_H + + +/* This file describes the Kexec / Kdump hypercall interface for Xen. + * + * Kexec under vanilla Linux allows a user to reboot the physical machine + * into a new user-specified kernel. The Xen port extends this idea + * to allow rebooting of the machine from dom0. When kexec for dom0 + * is used to reboot, both the hypervisor and the domains get replaced + * with some other kernel. It is possible to kexec between vanilla + * Linux and Xen and back again. Xen to Xen works well too. + * + * The hypercall interface for kexec can be divided into three main + * types of hypercall operations: + * + * 1) Range information: + * This is used by the dom0 kernel to ask the hypervisor about various + * address information. This information is needed to allow kexec-tools + * to fill in the ELF headers for /proc/vmcore properly. + * + * 2) Load and unload of images: + * There are no big surprises here, the kexec binary from kexec-tools + * runs in userspace in dom0. The tool loads/unloads data into the + * dom0 kernel such as new kernel, initramfs and hypervisor. When + * loaded the dom0 kernel performs a load hypercall operation, and + * before releasing all page references the dom0 kernel calls unload. + * + * 3) Kexec operation: + * This is used to start a previously loaded kernel. + */ + +#include "xen.h" + +/* + * Prototype for this hypercall is: + * int kexec_op(int cmd, void *args) + * @cmd == KEXEC_CMD_... + * KEXEC operation to perform + * @args == Operation-specific extra arguments (NULL if none). + */ + +/* + * Kexec supports two types of operation: + * - kexec into a regular kernel, very similar to a standard reboot + * - KEXEC_TYPE_DEFAULT is used to specify this type + * - kexec into a special "crash kernel", aka kexec-on-panic + * - KEXEC_TYPE_CRASH is used to specify this type + * - parts of our system may be broken at kexec-on-panic time + * - the code should be kept as simple and self-contained as possible + */ + +#define KEXEC_TYPE_DEFAULT 0 +#define KEXEC_TYPE_CRASH 1 + + +/* The kexec implementation for Xen allows the user to load two + * types of kernels, KEXEC_TYPE_DEFAULT and KEXEC_TYPE_CRASH. + * All data needed for a kexec reboot is kept in one xen_kexec_image_t + * per "instance". The data mainly consists of machine address lists to pages + * together with destination addresses. The data in xen_kexec_image_t + * is passed to the "code page" which is one page of code that performs + * the final relocations before jumping to the new kernel. + */ + +typedef struct xen_kexec_image { + unsigned long indirection_page; + unsigned long start_address; +} xen_kexec_image_t; + +/* + * Perform kexec having previously loaded a kexec or kdump kernel + * as appropriate. + * type == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH [in] + */ +#define KEXEC_CMD_kexec 0 +typedef struct xen_kexec_exec { + int type; +} xen_kexec_exec_t; + +/* + * Load/Unload kernel image for kexec or kdump. + * type == KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH [in] + * image == relocation information for kexec (ignored for unload) [in] + */ +#define KEXEC_CMD_kexec_load 1 +#define KEXEC_CMD_kexec_unload 2 +typedef struct xen_kexec_load { + int type; + xen_kexec_image_t image; +} xen_kexec_load_t; + +#define KEXEC_RANGE_MA_CRASH 0 /* machine address and size of crash area */ +#define KEXEC_RANGE_MA_XEN 1 /* machine address and size of Xen itself */ +#define KEXEC_RANGE_VA_XEN 2 /* virtual adrress and size of Xen itself */ +#define KEXEC_RANGE_MA_CPU 3 /* machine address and size of a CPU note */ + +/* + * Find the address and size of certain memory areas + * range == KEXEC_RANGE_... [in] + * nr == physical CPU number (starting from 0) if KEXEC_RANGE_MA_CPU [in] + * size == number of bytes reserved in window [out] + * start == address of the first byte in the window [out] + */ +#define KEXEC_CMD_kexec_get_range 3 +typedef struct xen_kexec_range { + int range; + int nr; + unsigned long size; + unsigned long start; +} xen_kexec_range_t; + +#endif /* _XEN_PUBLIC_KEXEC_H */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/elf.h b/xen/include/xen/elf.h index b7fb3c4d67..3728484c11 100644 --- a/xen/include/xen/elf.h +++ b/xen/include/xen/elf.h @@ -452,18 +452,12 @@ unsigned int elf_hash(const unsigned char *name); /* * Note Definitions */ -typedef struct { - Elf32_Word namesz; - Elf32_Word descsz; - Elf32_Word type; -} Elf32_Note; typedef struct { - Elf64_Half namesz; - Elf64_Half descsz; - Elf64_Half type; -} Elf64_Note; - + u32 namesz; + u32 descsz; + u32 type; +} Elf_Note; /* same format for both 32-bit and 64-bit ELF */ #if defined(ELFSIZE) #define CONCAT(x,y) __CONCAT(x,y) @@ -486,7 +480,6 @@ typedef struct { #define Elf_Addr Elf32_Addr #define Elf_Off Elf32_Off #define Elf_Nhdr Elf32_Nhdr -#define Elf_Note Elf32_Note #define ELF_R_SYM ELF32_R_SYM #define ELF_R_TYPE ELF32_R_TYPE @@ -511,7 +504,6 @@ typedef struct { #define Elf_Addr Elf64_Addr #define Elf_Off Elf64_Off #define Elf_Nhdr Elf64_Nhdr -#define Elf_Note Elf64_Note #define ELF_R_SYM ELF64_R_SYM #define ELF_R_TYPE ELF64_R_TYPE diff --git a/xen/include/xen/elfcore.h b/xen/include/xen/elfcore.h new file mode 100644 index 0000000000..158621ef64 --- /dev/null +++ b/xen/include/xen/elfcore.h @@ -0,0 +1,137 @@ +/****************************************************************************** + * elfcore.h + * + * Based heavily on include/linux/elfcore.h from Linux 2.6.16 + * Naming scheeme based on include/xen/elf.h (not include/linux/elfcore.h) + * + */ + +#ifndef __ELFCOREC_H__ +#define __ELFCOREC_H__ + +#include +#include +#include +#include + +#define NT_PRSTATUS 1 + +typedef struct +{ + int signo; /* signal number */ + int code; /* extra code */ + int errno; /* errno */ +} ELF_Signifo; + +/* These seem to be the same length on all architectures on Linux */ +typedef int ELF_Pid; +typedef struct { + long tv_sec; + long tv_usec; +} ELF_Timeval; + +/* + * Definitions to generate Intel SVR4-like core files. + * These mostly have the same names as the SVR4 types with "elf_" + * tacked on the front to prevent clashes with linux definitions, + * and the typedef forms have been avoided. This is mostly like + * the SVR4 structure, but more Linuxy, with things that Linux does + * not support and which gdb doesn't really use excluded. + */ +typedef struct +{ + ELF_Signifo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + unsigned long pr_sigpend; /* Set of pending signals */ + unsigned long pr_sighold; /* Set of held signals */ + ELF_Pid pr_pid; + ELF_Pid pr_ppid; + ELF_Pid pr_pgrp; + ELF_Pid pr_sid; + ELF_Timeval pr_utime; /* User time */ + ELF_Timeval pr_stime; /* System time */ + ELF_Timeval pr_cutime; /* Cumulative user time */ + ELF_Timeval pr_cstime; /* Cumulative system time */ + ELF_Gregset pr_reg; /* GP registers - from asm header file */ + int pr_fpvalid; /* True if math co-processor being used. */ +} ELF_Prstatus; + +/* + * The following data structures provide 64-bit ELF notes. In theory it should + * be possible to support both 64-bit and 32-bit ELF files, but to keep it + * simple we only do 64-bit. + * + * Please note that the current code aligns the 64-bit notes in the same + * way as Linux does. We are not following the 64-bit ELF spec, no one does. + * + * We are avoiding two problems by restricting us to 64-bit notes only: + * - Alignment of notes change with the word size. Ick. + * - We would need to tell kexec-tools which format we are using in the + * hypervisor to make sure the right ELF format is generated. + * That requires infrastructure. Let's not. + */ + +#define ALIGN(x, n) ((x + ((1 << n) - 1)) / (1 << n)) +#define PAD32(x) u32 pad_data[ALIGN(x, 2)] + +#define TYPEDEF_NOTE(type, strlen, desctype) \ + typedef struct { \ + union { \ + struct { \ + Elf_Note note; \ + unsigned char name[strlen]; \ + } note; \ + PAD32(sizeof(Elf_Note) + strlen); \ + } note; \ + union { \ + desctype desc; \ + PAD32(sizeof(desctype)); \ + } desc; \ + } __attribute__ ((packed)) type + +#define CORE_STR "CORE" +#define CORE_STR_LEN 5 /* including terminating zero */ + +TYPEDEF_NOTE(crash_note_core_t, CORE_STR_LEN, ELF_Prstatus); + +#define XEN_STR "Xen" +#define XEN_STR_LEN 4 /* including terminating zero */ + +TYPEDEF_NOTE(crash_note_xen_core_t, XEN_STR_LEN, crash_xen_core_t); + +typedef struct { + unsigned long xen_major_version; + unsigned long xen_minor_version; + unsigned long xen_extra_version; + unsigned long xen_changeset; + unsigned long xen_compiler; + unsigned long xen_compile_date; + unsigned long xen_compile_time; + unsigned long tainted; +} crash_xen_info_t; + +TYPEDEF_NOTE(crash_note_xen_info_t, XEN_STR_LEN, crash_xen_info_t); + +typedef struct { + crash_note_core_t core; + crash_note_xen_core_t xen_regs; + crash_note_xen_info_t xen_info; +} __attribute__ ((packed)) crash_note_t; + +#define setup_crash_note(np, member, str, str_len, id) \ + np->member.note.note.note.namesz = str_len; \ + np->member.note.note.note.descsz = sizeof(np->member.desc.desc); \ + np->member.note.note.note.type = id; \ + memcpy(np->member.note.note.name, str, str_len) + +#endif /* __ELFCOREC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h index 16cde7b738..b8fc94d2c6 100644 --- a/xen/include/xen/hypercall.h +++ b/xen/include/xen/hypercall.h @@ -102,4 +102,10 @@ do_hvm_op( unsigned long op, XEN_GUEST_HANDLE(void) arg); +extern long +do_kexec_op( + unsigned long op, + int arg1, + XEN_GUEST_HANDLE(void) arg); + #endif /* __XEN_HYPERCALL_H__ */ diff --git a/xen/include/xen/kexec.h b/xen/include/xen/kexec.h new file mode 100644 index 0000000000..cebc2d793a --- /dev/null +++ b/xen/include/xen/kexec.h @@ -0,0 +1,43 @@ +#ifndef __XEN_KEXEC_H__ +#define __XEN_KEXEC_H__ + +#include +#include +#include + +extern int crashing_cpu; + +typedef struct xen_kexec_reserve { + unsigned long size; + unsigned long start; +} xen_kexec_reserve_t; + +/* We have space for 4 images to support atomic update + * of images. This is important for CRASH images since + * a panic can happen at any time... + */ + +#define KEXEC_IMAGE_DEFAULT_BASE 0 +#define KEXEC_IMAGE_CRASH_BASE 2 +#define KEXEC_IMAGE_NR 4 + +int machine_kexec_load(int type, int slot, xen_kexec_image_t *image); +void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image); +void machine_kexec_reserved(xen_kexec_reserve_t *reservation); +void machine_shutdown(xen_kexec_image_t *image); +void machine_crash_kexec(void); +void machine_crash_save_cpu(void); +crash_xen_info_t *machine_crash_save_info(void); +void machine_crash_shutdown(void); + +#endif /* __XEN_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h index 7b9f76dea2..2326b70442 100644 --- a/xen/include/xen/mm.h +++ b/xen/include/xen/mm.h @@ -40,6 +40,7 @@ struct page_info; paddr_t init_boot_allocator(paddr_t bitmap_start); void init_boot_pages(paddr_t ps, paddr_t pe); unsigned long alloc_boot_pages(unsigned long nr_pfns, unsigned long pfn_align); +unsigned long alloc_boot_pages_at(unsigned long nr_pfns, unsigned long pfn_at); void end_boot_allocator(void); /* Generic allocator. These functions are *not* interrupt-safe. */ From 6dd60f6880df6d369385bdac2e41a5b6211423d9 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:38:51 +0000 Subject: [PATCH 070/282] [XEN] Kexec / Kdump: Code shared between x86_32 and x86_64 This patch contains Kexec / Kdump code shared between x86_32 and x86_64. Signed-Off-By: Magnus Damm Signed-Off-By: Simon Horman --- ...3d5b65e86ec1dfef7d268c64a909eab94af7.patch | 62 ++++++++++ ...55a9cec8418f0e0cde3dc3787a42fddc4411.patch | 93 ++++++++++++++ patches/linux-2.6.16.33/series | 2 + xen/arch/x86/crash.c | 115 +++++++++++++++++- xen/arch/x86/machine_kexec.c | 83 +++++++++++-- xen/arch/x86/setup.c | 73 +++++++++-- xen/arch/x86/traps.c | 2 + xen/include/asm-x86/elf.h | 18 +-- xen/include/asm-x86/fixmap.h | 4 + xen/include/asm-x86/hypercall.h | 5 + xen/include/asm-x86/kexec.h | 14 +-- xen/include/asm-x86/x86_32/elf.h | 26 ++++ xen/include/asm-x86/x86_32/kexec.h | 24 ++++ xen/include/asm-x86/x86_64/elf.h | 26 ++++ xen/include/asm-x86/x86_64/kexec.h | 24 ++++ xen/include/public/kexec.h | 7 ++ xen/include/xen/elfcore.h | 3 + 17 files changed, 538 insertions(+), 43 deletions(-) create mode 100644 patches/linux-2.6.16.33/git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch create mode 100644 patches/linux-2.6.16.33/git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch create mode 100644 xen/include/asm-x86/x86_32/elf.h create mode 100644 xen/include/asm-x86/x86_32/kexec.h create mode 100644 xen/include/asm-x86/x86_64/elf.h create mode 100644 xen/include/asm-x86/x86_64/kexec.h diff --git a/patches/linux-2.6.16.33/git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch b/patches/linux-2.6.16.33/git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch new file mode 100644 index 0000000000..3e7c024b38 --- /dev/null +++ b/patches/linux-2.6.16.33/git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch @@ -0,0 +1,62 @@ +From: Eric W. Biederman +Date: Sun, 30 Jul 2006 10:03:20 +0000 (-0700) +Subject: [PATCH] machine_kexec.c: Fix the description of segment handling +X-Git-Tag: v2.6.18-rc4 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=2a8a3d5b65e86ec1dfef7d268c64a909eab94af7 + +[PATCH] machine_kexec.c: Fix the description of segment handling + +One of my original comments in machine_kexec was unclear +and this should fix it. + +Signed-off-by: Eric W. Biederman +Cc: Andi Kleen +Acked-by: Horms +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + +--- a/arch/i386/kernel/machine_kexec.c ++++ b/arch/i386/kernel/machine_kexec.c +@@ -189,14 +189,11 @@ NORET_TYPE void machine_kexec(struct kim + memcpy((void *)reboot_code_buffer, relocate_new_kernel, + relocate_new_kernel_size); + +- /* The segment registers are funny things, they are +- * automatically loaded from a table, in memory wherever you +- * set them to a specific selector, but this table is never +- * accessed again you set the segment to a different selector. +- * +- * The more common model is are caches where the behide +- * the scenes work is done, but is also dropped at arbitrary +- * times. ++ /* The segment registers are funny things, they have both a ++ * visible and an invisible part. Whenever the visible part is ++ * set to a specific selector, the invisible part is loaded ++ * with from a table in memory. At no other time is the ++ * descriptor table in memory accessed. + * + * I take advantage of this here by force loading the + * segments, before I zap the gdt with an invalid value. +--- a/arch/x86_64/kernel/machine_kexec.c ++++ b/arch/x86_64/kernel/machine_kexec.c +@@ -207,14 +207,11 @@ NORET_TYPE void machine_kexec(struct kim + __flush_tlb(); + + +- /* The segment registers are funny things, they are +- * automatically loaded from a table, in memory wherever you +- * set them to a specific selector, but this table is never +- * accessed again unless you set the segment to a different selector. +- * +- * The more common model are caches where the behide +- * the scenes work is done, but is also dropped at arbitrary +- * times. ++ /* The segment registers are funny things, they have both a ++ * visible and an invisible part. Whenever the visible part is ++ * set to a specific selector, the invisible part is loaded ++ * with from a table in memory. At no other time is the ++ * descriptor table in memory accessed. + * + * I take advantage of this here by force loading the + * segments, before I zap the gdt with an invalid value. diff --git a/patches/linux-2.6.16.33/git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch b/patches/linux-2.6.16.33/git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch new file mode 100644 index 0000000000..9d0b701ffb --- /dev/null +++ b/patches/linux-2.6.16.33/git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch @@ -0,0 +1,93 @@ +From: Tobias Klauser +Date: Mon, 26 Jun 2006 16:57:34 +0000 (+0200) +Subject: Storage class should be first +X-Git-Tag: v2.6.18-rc1 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=2efe55a9cec8418f0e0cde3dc3787a42fddc4411 + +Storage class should be first + +Storage class should be before const + +Signed-off-by: Tobias Klauser +Signed-off-by: Adrian Bunk +--- + +--- a/arch/i386/kernel/machine_kexec.c ++++ b/arch/i386/kernel/machine_kexec.c +@@ -133,9 +133,9 @@ typedef asmlinkage NORET_TYPE void (*rel + unsigned long start_address, + unsigned int has_pae) ATTRIB_NORET; + +-const extern unsigned char relocate_new_kernel[]; ++extern const unsigned char relocate_new_kernel[]; + extern void relocate_new_kernel_end(void); +-const extern unsigned int relocate_new_kernel_size; ++extern const unsigned int relocate_new_kernel_size; + + /* + * A architecture hook called to validate the +--- a/arch/powerpc/kernel/machine_kexec_32.c ++++ b/arch/powerpc/kernel/machine_kexec_32.c +@@ -30,8 +30,8 @@ typedef NORET_TYPE void (*relocate_new_k + */ + void default_machine_kexec(struct kimage *image) + { +- const extern unsigned char relocate_new_kernel[]; +- const extern unsigned int relocate_new_kernel_size; ++ extern const unsigned char relocate_new_kernel[]; ++ extern const unsigned int relocate_new_kernel_size; + unsigned long page_list; + unsigned long reboot_code_buffer, reboot_code_buffer_phys; + relocate_new_kernel_t rnk; +--- a/arch/ppc/kernel/machine_kexec.c ++++ b/arch/ppc/kernel/machine_kexec.c +@@ -25,8 +25,8 @@ typedef NORET_TYPE void (*relocate_new_k + unsigned long reboot_code_buffer, + unsigned long start_address) ATTRIB_NORET; + +-const extern unsigned char relocate_new_kernel[]; +-const extern unsigned int relocate_new_kernel_size; ++extern const unsigned char relocate_new_kernel[]; ++extern const unsigned int relocate_new_kernel_size; + + void machine_shutdown(void) + { +--- a/arch/s390/kernel/machine_kexec.c ++++ b/arch/s390/kernel/machine_kexec.c +@@ -27,8 +27,8 @@ static void kexec_halt_all_cpus(void *); + + typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long); + +-const extern unsigned char relocate_kernel[]; +-const extern unsigned long long relocate_kernel_len; ++extern const unsigned char relocate_kernel[]; ++extern const unsigned long long relocate_kernel_len; + + int + machine_kexec_prepare(struct kimage *image) +--- a/arch/sh/kernel/machine_kexec.c ++++ b/arch/sh/kernel/machine_kexec.c +@@ -25,8 +25,8 @@ typedef NORET_TYPE void (*relocate_new_k + unsigned long start_address, + unsigned long vbr_reg) ATTRIB_NORET; + +-const extern unsigned char relocate_new_kernel[]; +-const extern unsigned int relocate_new_kernel_size; ++extern const unsigned char relocate_new_kernel[]; ++extern const unsigned int relocate_new_kernel_size; + extern void *gdb_vbr_vector; + + /* +--- a/arch/x86_64/kernel/machine_kexec.c ++++ b/arch/x86_64/kernel/machine_kexec.c +@@ -149,8 +149,8 @@ typedef NORET_TYPE void (*relocate_new_k + unsigned long start_address, + unsigned long pgtable) ATTRIB_NORET; + +-const extern unsigned char relocate_new_kernel[]; +-const extern unsigned long relocate_new_kernel_size; ++extern const unsigned char relocate_new_kernel[]; ++extern const unsigned long relocate_new_kernel_size; + + int machine_kexec_prepare(struct kimage *image) + { diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index 8d3ec1a0df..025a7be77d 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -1,4 +1,6 @@ kexec-generic.patch +git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch +git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c index f1729786ea..73ed160021 100644 --- a/xen/arch/x86/crash.c +++ b/xen/arch/x86/crash.c @@ -1,10 +1,119 @@ -#include /* for printk() used in stub */ +/****************************************************************************** + * crash.c + * + * Based heavily on arch/i386/kernel/crash.c from Linux 2.6.16 + * + * Xen port written by: + * - Simon 'Horms' Horman + * - Magnus Damm + */ + +#include +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_SMP +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct cpu_user_regs *regs, int cpu) +{ + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return 1; + local_irq_disable(); + + machine_crash_save_cpu(); + disable_local_APIC(); + atomic_dec(&waiting_for_crash_ipi); + hvm_disable(); + + for ( ; ; ) + __asm__ __volatile__ ( "hlt" ); + + return 1; +} + +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +static void smp_send_nmi_allbutself(void) +{ + cpumask_t allbutself = cpu_online_map; + + cpu_clear(smp_processor_id(), allbutself); + send_IPI_mask(allbutself, APIC_DM_NMI); +} + +static void nmi_shootdown_cpus(void) +{ + unsigned long msecs; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + set_nmi_callback(crash_nmi_callback); + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + /* Leave the nmi callback set */ + disable_local_APIC(); +} +#endif + +static void crash_save_xen_notes(void) +{ + crash_xen_info_t *info; + + info = machine_crash_save_info(); + + info->dom0_pfn_to_mfn_frame_list_list = \ + dom0->shared_info->arch.pfn_to_mfn_frame_list_list; +} void machine_crash_shutdown(void) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + printk("machine_crash_shutdown: %d\n", smp_processor_id()); + local_irq_disable(); + +#ifdef CONFIG_SMP + nmi_shootdown_cpus(); +#endif + +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif + hvm_disable(); + + crash_save_xen_notes(); } /* diff --git a/xen/arch/x86/machine_kexec.c b/xen/arch/x86/machine_kexec.c index 639f845ac1..f60296271d 100644 --- a/xen/arch/x86/machine_kexec.c +++ b/xen/arch/x86/machine_kexec.c @@ -1,26 +1,89 @@ -#include /* for printk() used in stubs */ +/****************************************************************************** + * machine_kexec.c + * + * Xen port written by: + * - Simon 'Horms' Horman + * - Magnus Damm + */ + +#include +#include +#include +#include +#include +#include #include -#include +#include +#include +#include +#include +#include +#include int machine_kexec_load(int type, int slot, xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); - return -1; + unsigned long prev_ma = 0; + int fix_base = FIX_KEXEC_BASE_0 + (slot * (KEXEC_XEN_NO_PAGES >> 1)); + int k; + + /* setup fixmap to point to our pages and record the virtual address + * in every odd index in page_list[]. + */ + + for (k = 0; k < KEXEC_XEN_NO_PAGES; k++) { + if ((k & 1) == 0) { /* even pages: machine address */ + prev_ma = image->page_list[k]; + } + else { /* odd pages: va for previous ma */ + set_fixmap(fix_base + (k >> 1), prev_ma); + image->page_list[k] = fix_to_virt(fix_base + (k >> 1)); + } + } + + return 0; } void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } - -void machine_kexec(xen_kexec_image_t *image) + +static void __machine_shutdown(void *data) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); -} + xen_kexec_image_t *image = (xen_kexec_image_t *)data; + watchdog_disable(); + console_start_sync(); + + smp_send_stop(); + +#ifdef CONFIG_X86_IO_APIC + disable_IO_APIC(); +#endif + hvm_disable(); + + machine_kexec(image); +} + void machine_shutdown(xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + int reboot_cpu_id; + cpumask_t reboot_cpu; + + reboot_cpu_id = 0; + + if (!cpu_isset(reboot_cpu_id, cpu_online_map)) + reboot_cpu_id = smp_processor_id(); + + if (reboot_cpu_id != smp_processor_id()) { + cpus_clear(reboot_cpu); + cpu_set(reboot_cpu_id, reboot_cpu); + on_selected_cpus(reboot_cpu, __machine_shutdown, image, 1, 0); + for (;;) + ; /* nothing */ + } + else + __machine_shutdown(image); + BUG(); } /* diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index e144b6ca47..181ca84f5f 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -27,6 +27,7 @@ #include #include #include +#include extern void dmi_scan_machine(void); extern void generic_apic_probe(void); @@ -273,6 +274,20 @@ static void srat_detect_node(int cpu) printk(KERN_INFO "CPU %d APIC %d -> Node %d\n", cpu, apicid, node); } +void __init move_memory(unsigned long dst, + unsigned long src_start, unsigned long src_end) +{ +#if defined(CONFIG_X86_32) + memmove((void *)dst, /* use low mapping */ + (void *)src_start, /* use low mapping */ + src_end - src_start); +#elif defined(CONFIG_X86_64) + memmove(__va(dst), + __va(src_start), + src_end - src_start); +#endif +} + void __init __start_xen(multiboot_info_t *mbi) { char __cmdline[] = "", *cmdline = __cmdline; @@ -284,6 +299,7 @@ void __init __start_xen(multiboot_info_t *mbi) unsigned long nr_pages, modules_length; paddr_t s, e; int i, e820_warn = 0, e820_raw_nr = 0, bytes = 0; + xen_kexec_reserve_t crash_area; struct ns16550_defaults ns16550 = { .data_bits = 8, .parity = 'n', @@ -415,15 +431,8 @@ void __init __start_xen(multiboot_info_t *mbi) initial_images_start = xenheap_phys_end; initial_images_end = initial_images_start + modules_length; -#if defined(CONFIG_X86_32) - memmove((void *)initial_images_start, /* use low mapping */ - (void *)mod[0].mod_start, /* use low mapping */ - mod[mbi->mods_count-1].mod_end - mod[0].mod_start); -#elif defined(CONFIG_X86_64) - memmove(__va(initial_images_start), - __va(mod[0].mod_start), - mod[mbi->mods_count-1].mod_end - mod[0].mod_start); -#endif + move_memory(initial_images_start, + mod[0].mod_start, mod[mbi->mods_count-1].mod_end); /* Initialise boot-time allocator with all RAM situated after modules. */ xenheap_phys_start = init_boot_allocator(__pa(&_end)); @@ -471,6 +480,52 @@ void __init __start_xen(multiboot_info_t *mbi) #endif } + machine_kexec_reserved(&crash_area); + if (crash_area.size > 0) { + unsigned long kdump_start, kdump_size, k; + + /* mark images pages as free for now */ + + init_boot_pages(initial_images_start, initial_images_end); + + kdump_start = crash_area.start; + kdump_size = crash_area.size; + + printk("Kdump: %luMB (%lukB) at 0x%lx\n", + kdump_size >> 20, + kdump_size >> 10, + kdump_start); + + if ((kdump_start & ~PAGE_MASK) || (kdump_size & ~PAGE_MASK)) + panic("Kdump parameters not page aligned\n"); + + kdump_start >>= PAGE_SHIFT; + kdump_size >>= PAGE_SHIFT; + + /* allocate pages for Kdump memory area */ + + k = alloc_boot_pages_at(kdump_size, kdump_start); + + if (k != kdump_start) + panic("Unable to reserve Kdump memory\n"); + + /* allocate pages for relocated initial images */ + + k = ((initial_images_end - initial_images_start) & ~PAGE_MASK) ? 1 : 0; + k += (initial_images_end - initial_images_start) >> PAGE_SHIFT; + + k = alloc_boot_pages(k, 1); + + if (!k) + panic("Unable to allocate initial images memory\n"); + + move_memory(k << PAGE_SHIFT, initial_images_start, initial_images_end); + + initial_images_end -= initial_images_start; + initial_images_start = k << PAGE_SHIFT; + initial_images_end += initial_images_start; + } + memguard_init(); percpu_guard_areas(); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 87f3f79491..3e6ab2856d 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -1633,6 +1634,7 @@ static void unknown_nmi_error(unsigned char reason) printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); printk("Dazed and confused, but trying to continue\n"); printk("Do you have a strange power saving mode enabled?\n"); + machine_crash_kexec(); } } diff --git a/xen/include/asm-x86/elf.h b/xen/include/asm-x86/elf.h index bfd7913d10..9747d46e61 100644 --- a/xen/include/asm-x86/elf.h +++ b/xen/include/asm-x86/elf.h @@ -1,21 +1,15 @@ #ifndef __X86_ELF_H__ #define __X86_ELF_H__ -#include /* for printk() used in stub */ - typedef struct { - unsigned long dummy; -} ELF_Gregset; - -typedef struct { - unsigned long dummy; + unsigned long cr0, cr2, cr3, cr4; } crash_xen_core_t; -extern inline void elf_core_save_regs(ELF_Gregset *core_regs, - crash_xen_core_t *xen_core_regs) -{ - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); -} +#ifdef __x86_64__ +#include +#else +#include +#endif #endif /* __X86_ELF_H__ */ diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h index dbf1b70c55..8444e21262 100644 --- a/xen/include/asm-x86/fixmap.h +++ b/xen/include/asm-x86/fixmap.h @@ -16,6 +16,7 @@ #include #include #include +#include /* * Here we define all the compile-time 'special' virtual @@ -36,6 +37,9 @@ enum fixed_addresses { FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, FIX_HPET_BASE, FIX_CYCLONE_TIMER, + FIX_KEXEC_BASE_0, + FIX_KEXEC_BASE_END = FIX_KEXEC_BASE_0 \ + + ((KEXEC_XEN_NO_PAGES >> 1) * KEXEC_IMAGE_NR) - 1, __end_of_fixed_addresses }; diff --git a/xen/include/asm-x86/hypercall.h b/xen/include/asm-x86/hypercall.h index 69d7ba793d..860fb2ce77 100644 --- a/xen/include/asm-x86/hypercall.h +++ b/xen/include/asm-x86/hypercall.h @@ -6,6 +6,7 @@ #define __ASM_X86_HYPERCALL_H__ #include +#include extern long do_event_channel_op_compat( @@ -87,6 +88,10 @@ extern long arch_do_vcpu_op( int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg); +extern int +do_kexec( + unsigned long op, unsigned arg1, XEN_GUEST_HANDLE(void) uarg); + #ifdef __x86_64__ extern long diff --git a/xen/include/asm-x86/kexec.h b/xen/include/asm-x86/kexec.h index ba47dbf6dc..d137337da0 100644 --- a/xen/include/asm-x86/kexec.h +++ b/xen/include/asm-x86/kexec.h @@ -1,15 +1,11 @@ #ifndef __X86_KEXEC_H__ #define __X86_KEXEC_H__ -#include /* for printk() used in stub */ -#include -#include -#include - -static inline void machine_kexec(xen_kexec_image_t *image) -{ - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); -} +#ifdef __x86_64__ +#include +#else +#include +#endif #endif /* __X86_KEXEC_H__ */ diff --git a/xen/include/asm-x86/x86_32/elf.h b/xen/include/asm-x86/x86_32/elf.h new file mode 100644 index 0000000000..982906cace --- /dev/null +++ b/xen/include/asm-x86/x86_32/elf.h @@ -0,0 +1,26 @@ +#ifndef __X86_32_ELF_H__ +#define __X86_32_ELF_H__ + +#include /* for printk() used in stub */ + +typedef struct { + unsigned long dummy; +} ELF_Gregset; + +extern inline void elf_core_save_regs(ELF_Gregset *core_regs, + crash_xen_core_t *xen_core_regs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __X86_32_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-x86/x86_32/kexec.h b/xen/include/asm-x86/x86_32/kexec.h new file mode 100644 index 0000000000..97bbab8bb2 --- /dev/null +++ b/xen/include/asm-x86/x86_32/kexec.h @@ -0,0 +1,24 @@ +#ifndef __X86_32_KEXEC_H__ +#define __X86_32_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include +#include + +static inline void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __X86_32_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-x86/x86_64/elf.h b/xen/include/asm-x86/x86_64/elf.h new file mode 100644 index 0000000000..8068c3ab5d --- /dev/null +++ b/xen/include/asm-x86/x86_64/elf.h @@ -0,0 +1,26 @@ +#ifndef __X86_64_ELF_H__ +#define __X86_64_ELF_H__ + +#include /* for printk() used in stub */ + +typedef struct { + unsigned long dummy; +} ELF_Gregset; + +extern inline void elf_core_save_regs(ELF_Gregset *core_regs, + crash_xen_core_t *xen_core_regs) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __X86_64_ELF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-x86/x86_64/kexec.h b/xen/include/asm-x86/x86_64/kexec.h new file mode 100644 index 0000000000..3433ba7846 --- /dev/null +++ b/xen/include/asm-x86/x86_64/kexec.h @@ -0,0 +1,24 @@ +#ifndef __X86_64_KEXEC_H__ +#define __X86_64_KEXEC_H__ + +#include /* for printk() used in stub */ +#include +#include +#include + +static inline void machine_kexec(xen_kexec_image_t *image) +{ + printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); +} + +#endif /* __X86_64_KEXEC_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h index c51f24ccdd..556aaecb3d 100644 --- a/xen/include/public/kexec.h +++ b/xen/include/public/kexec.h @@ -40,6 +40,10 @@ #include "xen.h" +#if defined(__i386__) || defined(__x86_64__) +#define KEXEC_XEN_NO_PAGES 17 +#endif + /* * Prototype for this hypercall is: * int kexec_op(int cmd, void *args) @@ -72,6 +76,9 @@ */ typedef struct xen_kexec_image { +#if defined(__i386__) || defined(__x86_64__) + unsigned long page_list[KEXEC_XEN_NO_PAGES]; +#endif unsigned long indirection_page; unsigned long start_address; } xen_kexec_image_t; diff --git a/xen/include/xen/elfcore.h b/xen/include/xen/elfcore.h index 158621ef64..d578d0dd0b 100644 --- a/xen/include/xen/elfcore.h +++ b/xen/include/xen/elfcore.h @@ -108,6 +108,9 @@ typedef struct { unsigned long xen_compile_date; unsigned long xen_compile_time; unsigned long tainted; +#ifdef CONFIG_X86 + unsigned long dom0_pfn_to_mfn_frame_list_list; +#endif } crash_xen_info_t; TYPEDEF_NOTE(crash_note_xen_info_t, XEN_STR_LEN, crash_xen_info_t); From 92491dae02f30ee1d0b65c8ca425adf8dc1b0daf Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:38:51 +0000 Subject: [PATCH 071/282] [XEN] Kexec / Kdump: x86_32 specific code This patch contains the x86_32 implementation of Kexec / Kdump for Xen. Signed-Off-By: Magnus Damm Signed-Off-By: Simon Horman --- buildconfigs/linux-defconfig_xen_x86_32 | 2 + linux-2.6-xen-sparse/arch/i386/Kconfig | 2 +- .../arch/i386/kernel/setup-xen.c | 19 +- .../include/asm-i386/mach-xen/asm/hypercall.h | 8 + ...561bfadffcb5dbc85d576be80c0dbf2cccc9.patch | 401 ++++++++++++++++++ ....19-rc1-kexec-move_segment_code-i386.patch | 169 ++++++++ .../linux-2.6.19-rc1-kexec-xen-i386.patch | 108 +++++ patches/linux-2.6.16.33/series | 3 + xen/arch/x86/x86_32/entry.S | 2 + xen/include/asm-x86/x86_32/elf.h | 52 ++- xen/include/asm-x86/x86_32/kexec.h | 28 +- 11 files changed, 783 insertions(+), 11 deletions(-) create mode 100644 patches/linux-2.6.16.33/git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch create mode 100644 patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch create mode 100644 patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch diff --git a/buildconfigs/linux-defconfig_xen_x86_32 b/buildconfigs/linux-defconfig_xen_x86_32 index 0dee9d8734..6128a1012b 100644 --- a/buildconfigs/linux-defconfig_xen_x86_32 +++ b/buildconfigs/linux-defconfig_xen_x86_32 @@ -184,6 +184,7 @@ CONFIG_MTRR=y CONFIG_REGPARM=y CONFIG_SECCOMP=y CONFIG_HZ_100=y +CONFIG_KEXEC=y # CONFIG_HZ_250 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 @@ -2776,6 +2777,7 @@ CONFIG_NTFS_FS=m # CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y +# CONFIG_PROC_VMCORE is not set CONFIG_SYSFS=y CONFIG_TMPFS=y # CONFIG_HUGETLB_PAGE is not set diff --git a/linux-2.6-xen-sparse/arch/i386/Kconfig b/linux-2.6-xen-sparse/arch/i386/Kconfig index b3ef1013c4..8c712269d0 100644 --- a/linux-2.6-xen-sparse/arch/i386/Kconfig +++ b/linux-2.6-xen-sparse/arch/i386/Kconfig @@ -726,7 +726,7 @@ source kernel/Kconfig.hz config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL && !X86_XEN + depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c index 2586296dbb..252e5c4ec2 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c @@ -69,6 +69,10 @@ #include "setup_arch_pre.h" #include +#ifdef CONFIG_XEN +#include +#endif + /* Forward Declaration. */ void __init find_max_pfn(void); @@ -943,6 +947,7 @@ static void __init parse_cmdline_early (char ** cmdline_p) * after a kernel panic. */ else if (!memcmp(from, "crashkernel=", 12)) { +#ifndef CONFIG_XEN unsigned long size, base; size = memparse(from+12, &from); if (*from == '@') { @@ -953,6 +958,10 @@ static void __init parse_cmdline_early (char ** cmdline_p) crashk_res.start = base; crashk_res.end = base + size - 1; } +#else + printk("Ignoring crashkernel command line, " + "parameter will be supplied by xen\n"); +#endif } #endif #ifdef CONFIG_PROC_VMCORE @@ -1322,9 +1331,13 @@ void __init setup_bootmem_allocator(void) } #endif #ifdef CONFIG_KEXEC +#ifdef CONFIG_XEN + xen_machine_kexec_setup_resources(); +#else if (crashk_res.start != crashk_res.end) reserve_bootmem(crashk_res.start, crashk_res.end - crashk_res.start + 1); +#endif #endif if (!xen_feature(XENFEAT_auto_translated_physmap)) @@ -1389,7 +1402,11 @@ legacy_init_iomem_resources(struct e820entry *e820, int nr_map, request_resource(res, data_resource); #endif #ifdef CONFIG_KEXEC - request_resource(res, &crashk_res); + if (crashk_res.start != crashk_res.end) + request_resource(res, &crashk_res); +#ifdef CONFIG_XEN + xen_machine_kexec_register_resources(res); +#endif #endif } } diff --git a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h index a12e349016..c3ed3584b6 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/hypercall.h @@ -395,5 +395,13 @@ HYPERVISOR_xenoprof_op( return _hypercall2(int, xenoprof_op, op, arg); } +static inline int +HYPERVISOR_kexec_op( + unsigned long op, void *args) +{ + return _hypercall2(int, kexec_op, op, args); +} + + #endif /* __HYPERCALL_H__ */ diff --git a/patches/linux-2.6.16.33/git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch b/patches/linux-2.6.16.33/git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch new file mode 100644 index 0000000000..f0650a1bb4 --- /dev/null +++ b/patches/linux-2.6.16.33/git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch @@ -0,0 +1,401 @@ +From: Magnus Damm +Date: Tue, 26 Sep 2006 08:52:38 +0000 (+0200) +Subject: [PATCH] i386: Avoid overwriting the current pgd (V4, i386) +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=3566561bfadffcb5dbc85d576be80c0dbf2cccc9 + +[PATCH] i386: Avoid overwriting the current pgd (V4, i386) + +kexec: Avoid overwriting the current pgd (V4, i386) + +This patch upgrades the i386-specific kexec code to avoid overwriting the +current pgd. Overwriting the current pgd is bad when CONFIG_CRASH_DUMP is used +to start a secondary kernel that dumps the memory of the previous kernel. + +The code introduces a new set of page tables. These tables are used to provide +an executable identity mapping without overwriting the current pgd. + +Signed-off-by: Magnus Damm +Signed-off-by: Andi Kleen +--- + +--- a/arch/i386/kernel/machine_kexec.c ++++ b/arch/i386/kernel/machine_kexec.c +@@ -21,70 +21,13 @@ + #include + + #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) +- +-#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +-#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) +-#define L2_ATTR (_PAGE_PRESENT) +- +-#define LEVEL0_SIZE (1UL << 12UL) +- +-#ifndef CONFIG_X86_PAE +-#define LEVEL1_SIZE (1UL << 22UL) +-static u32 pgtable_level1[1024] PAGE_ALIGNED; +- +-static void identity_map_page(unsigned long address) +-{ +- unsigned long level1_index, level2_index; +- u32 *pgtable_level2; +- +- /* Find the current page table */ +- pgtable_level2 = __va(read_cr3()); +- +- /* Find the indexes of the physical address to identity map */ +- level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; +- level2_index = address / LEVEL1_SIZE; +- +- /* Identity map the page table entry */ +- pgtable_level1[level1_index] = address | L0_ATTR; +- pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; +- +- /* Flush the tlb so the new mapping takes effect. +- * Global tlb entries are not flushed but that is not an issue. +- */ +- load_cr3(pgtable_level2); +-} +- +-#else +-#define LEVEL1_SIZE (1UL << 21UL) +-#define LEVEL2_SIZE (1UL << 30UL) +-static u64 pgtable_level1[512] PAGE_ALIGNED; +-static u64 pgtable_level2[512] PAGE_ALIGNED; +- +-static void identity_map_page(unsigned long address) +-{ +- unsigned long level1_index, level2_index, level3_index; +- u64 *pgtable_level3; +- +- /* Find the current page table */ +- pgtable_level3 = __va(read_cr3()); +- +- /* Find the indexes of the physical address to identity map */ +- level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; +- level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE; +- level3_index = address / LEVEL2_SIZE; +- +- /* Identity map the page table entry */ +- pgtable_level1[level1_index] = address | L0_ATTR; +- pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; +- set_64bit(&pgtable_level3[level3_index], +- __pa(pgtable_level2) | L2_ATTR); +- +- /* Flush the tlb so the new mapping takes effect. +- * Global tlb entries are not flushed but that is not an issue. +- */ +- load_cr3(pgtable_level3); +-} ++static u32 kexec_pgd[1024] PAGE_ALIGNED; ++#ifdef CONFIG_X86_PAE ++static u32 kexec_pmd0[1024] PAGE_ALIGNED; ++static u32 kexec_pmd1[1024] PAGE_ALIGNED; + #endif ++static u32 kexec_pte0[1024] PAGE_ALIGNED; ++static u32 kexec_pte1[1024] PAGE_ALIGNED; + + static void set_idt(void *newidt, __u16 limit) + { +@@ -128,16 +71,6 @@ static void load_segments(void) + #undef __STR + } + +-typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( +- unsigned long indirection_page, +- unsigned long reboot_code_buffer, +- unsigned long start_address, +- unsigned int has_pae) ATTRIB_NORET; +- +-extern const unsigned char relocate_new_kernel[]; +-extern void relocate_new_kernel_end(void); +-extern const unsigned int relocate_new_kernel_size; +- + /* + * A architecture hook called to validate the + * proposed image and prepare the control pages +@@ -170,25 +103,29 @@ void machine_kexec_cleanup(struct kimage + */ + NORET_TYPE void machine_kexec(struct kimage *image) + { +- unsigned long page_list; +- unsigned long reboot_code_buffer; +- +- relocate_new_kernel_t rnk; ++ unsigned long page_list[PAGES_NR]; ++ void *control_page; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + +- /* Compute some offsets */ +- reboot_code_buffer = page_to_pfn(image->control_code_page) +- << PAGE_SHIFT; +- page_list = image->head; +- +- /* Set up an identity mapping for the reboot_code_buffer */ +- identity_map_page(reboot_code_buffer); +- +- /* copy it out */ +- memcpy((void *)reboot_code_buffer, relocate_new_kernel, +- relocate_new_kernel_size); ++ control_page = page_address(image->control_code_page); ++ memcpy(control_page, relocate_kernel, PAGE_SIZE); ++ ++ page_list[PA_CONTROL_PAGE] = __pa(control_page); ++ page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; ++ page_list[PA_PGD] = __pa(kexec_pgd); ++ page_list[VA_PGD] = (unsigned long)kexec_pgd; ++#ifdef CONFIG_X86_PAE ++ page_list[PA_PMD_0] = __pa(kexec_pmd0); ++ page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; ++ page_list[PA_PMD_1] = __pa(kexec_pmd1); ++ page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; ++#endif ++ page_list[PA_PTE_0] = __pa(kexec_pte0); ++ page_list[VA_PTE_0] = (unsigned long)kexec_pte0; ++ page_list[PA_PTE_1] = __pa(kexec_pte1); ++ page_list[VA_PTE_1] = (unsigned long)kexec_pte1; + + /* The segment registers are funny things, they have both a + * visible and an invisible part. Whenever the visible part is +@@ -207,8 +144,8 @@ NORET_TYPE void machine_kexec(struct kim + set_idt(phys_to_virt(0),0); + + /* now call it */ +- rnk = (relocate_new_kernel_t) reboot_code_buffer; +- (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); ++ relocate_kernel((unsigned long)image->head, (unsigned long)page_list, ++ image->start, cpu_has_pae); + } + + /* crashkernel=size@addr specifies the location to reserve for +--- a/arch/i386/kernel/relocate_kernel.S ++++ b/arch/i386/kernel/relocate_kernel.S +@@ -7,16 +7,138 @@ + */ + + #include ++#include ++#include ++ ++/* ++ * Must be relocatable PIC code callable as a C function ++ */ ++ ++#define PTR(x) (x << 2) ++#define PAGE_ALIGNED (1 << PAGE_SHIFT) ++#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */ ++#define PAE_PGD_ATTR 0x01 /* _PAGE_PRESENT */ ++ ++ .text ++ .align PAGE_ALIGNED ++ .globl relocate_kernel ++relocate_kernel: ++ movl 8(%esp), %ebp /* list of pages */ ++ ++#ifdef CONFIG_X86_PAE ++ /* map the control page at its virtual address */ ++ ++ movl PTR(VA_PGD)(%ebp), %edi ++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax ++ andl $0xc0000000, %eax ++ shrl $27, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_PMD_0)(%ebp), %edx ++ orl $PAE_PGD_ATTR, %edx ++ movl %edx, (%eax) ++ ++ movl PTR(VA_PMD_0)(%ebp), %edi ++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax ++ andl $0x3fe00000, %eax ++ shrl $18, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_PTE_0)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++ ++ movl PTR(VA_PTE_0)(%ebp), %edi ++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax ++ andl $0x001ff000, %eax ++ shrl $9, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++ ++ /* identity map the control page at its physical address */ ++ ++ movl PTR(VA_PGD)(%ebp), %edi ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax ++ andl $0xc0000000, %eax ++ shrl $27, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_PMD_1)(%ebp), %edx ++ orl $PAE_PGD_ATTR, %edx ++ movl %edx, (%eax) ++ ++ movl PTR(VA_PMD_1)(%ebp), %edi ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax ++ andl $0x3fe00000, %eax ++ shrl $18, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_PTE_1)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++ ++ movl PTR(VA_PTE_1)(%ebp), %edi ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax ++ andl $0x001ff000, %eax ++ shrl $9, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++#else ++ /* map the control page at its virtual address */ ++ ++ movl PTR(VA_PGD)(%ebp), %edi ++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax ++ andl $0xffc00000, %eax ++ shrl $20, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_PTE_0)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++ ++ movl PTR(VA_PTE_0)(%ebp), %edi ++ movl PTR(VA_CONTROL_PAGE)(%ebp), %eax ++ andl $0x003ff000, %eax ++ shrl $10, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++ ++ /* identity map the control page at its physical address */ ++ ++ movl PTR(VA_PGD)(%ebp), %edi ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax ++ andl $0xffc00000, %eax ++ shrl $20, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_PTE_1)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++ ++ movl PTR(VA_PTE_1)(%ebp), %edi ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %eax ++ andl $0x003ff000, %eax ++ shrl $10, %eax ++ addl %edi, %eax ++ ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edx ++ orl $PAGE_ATTR, %edx ++ movl %edx, (%eax) ++#endif + +- /* +- * Must be relocatable PIC code callable as a C function, that once +- * it starts can not use the previous processes stack. +- */ +- .globl relocate_new_kernel + relocate_new_kernel: + /* read the arguments and say goodbye to the stack */ + movl 4(%esp), %ebx /* page_list */ +- movl 8(%esp), %ebp /* reboot_code_buffer */ ++ movl 8(%esp), %ebp /* list of pages */ + movl 12(%esp), %edx /* start address */ + movl 16(%esp), %ecx /* cpu_has_pae */ + +@@ -24,11 +146,26 @@ relocate_new_kernel: + pushl $0 + popfl + +- /* set a new stack at the bottom of our page... */ +- lea 4096(%ebp), %esp ++ /* get physical address of control page now */ ++ /* this is impossible after page table switch */ ++ movl PTR(PA_CONTROL_PAGE)(%ebp), %edi ++ ++ /* switch to new set of page tables */ ++ movl PTR(PA_PGD)(%ebp), %eax ++ movl %eax, %cr3 ++ ++ /* setup a new stack at the end of the physical control page */ ++ lea 4096(%edi), %esp + +- /* store the parameters back on the stack */ +- pushl %edx /* store the start address */ ++ /* jump to identity mapped page */ ++ movl %edi, %eax ++ addl $(identity_mapped - relocate_kernel), %eax ++ pushl %eax ++ ret ++ ++identity_mapped: ++ /* store the start address on the stack */ ++ pushl %edx + + /* Set cr0 to a known state: + * 31 0 == Paging disabled +@@ -113,8 +250,3 @@ relocate_new_kernel: + xorl %edi, %edi + xorl %ebp, %ebp + ret +-relocate_new_kernel_end: +- +- .globl relocate_new_kernel_size +-relocate_new_kernel_size: +- .long relocate_new_kernel_end - relocate_new_kernel +--- a/include/asm-i386/kexec.h ++++ b/include/asm-i386/kexec.h +@@ -1,6 +1,26 @@ + #ifndef _I386_KEXEC_H + #define _I386_KEXEC_H + ++#define PA_CONTROL_PAGE 0 ++#define VA_CONTROL_PAGE 1 ++#define PA_PGD 2 ++#define VA_PGD 3 ++#define PA_PTE_0 4 ++#define VA_PTE_0 5 ++#define PA_PTE_1 6 ++#define VA_PTE_1 7 ++#ifdef CONFIG_X86_PAE ++#define PA_PMD_0 8 ++#define VA_PMD_0 9 ++#define PA_PMD_1 10 ++#define VA_PMD_1 11 ++#define PAGES_NR 12 ++#else ++#define PAGES_NR 8 ++#endif ++ ++#ifndef __ASSEMBLY__ ++ + #include + #include + #include +@@ -72,5 +92,12 @@ static inline void crash_setup_regs(stru + newregs->eip = (unsigned long)current_text_addr(); + } + } ++asmlinkage NORET_TYPE void ++relocate_kernel(unsigned long indirection_page, ++ unsigned long control_page, ++ unsigned long start_address, ++ unsigned int has_pae) ATTRIB_NORET; ++ ++#endif /* __ASSEMBLY__ */ + + #endif /* _I386_KEXEC_H */ diff --git a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch new file mode 100644 index 0000000000..a0c9518f48 --- /dev/null +++ b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-i386.patch @@ -0,0 +1,169 @@ +kexec: Move asm segment handling code to the assembly file (i386) + +This patch moves the idt, gdt, and segment handling code from machine_kexec.c +to relocate_kernel.S. The main reason behind this move is to avoid code +duplication in the Xen hypervisor. With this patch all code required to kexec +is put on the control page. + +On top of that this patch also counts as a cleanup - I think it is much +nicer to write assembly directly in assembly files than wrap inline assembly +in C functions for no apparent reason. + +Signed-off-by: Magnus Damm +--- + + Applies to 2.6.19-rc1. + + machine_kexec.c | 59 ----------------------------------------------------- + relocate_kernel.S | 58 +++++++++++++++++++++++++++++++++++++++++++++++----- + 2 files changed, 53 insertions(+), 64 deletions(-) + +--- 0002/arch/i386/kernel/machine_kexec.c ++++ work/arch/i386/kernel/machine_kexec.c 2006-10-05 15:49:08.000000000 +0900 +@@ -29,48 +29,6 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED + static u32 kexec_pte0[1024] PAGE_ALIGNED; + static u32 kexec_pte1[1024] PAGE_ALIGNED; + +-static void set_idt(void *newidt, __u16 limit) +-{ +- struct Xgt_desc_struct curidt; +- +- /* ia32 supports unaliged loads & stores */ +- curidt.size = limit; +- curidt.address = (unsigned long)newidt; +- +- load_idt(&curidt); +-}; +- +- +-static void set_gdt(void *newgdt, __u16 limit) +-{ +- struct Xgt_desc_struct curgdt; +- +- /* ia32 supports unaligned loads & stores */ +- curgdt.size = limit; +- curgdt.address = (unsigned long)newgdt; +- +- load_gdt(&curgdt); +-}; +- +-static void load_segments(void) +-{ +-#define __STR(X) #X +-#define STR(X) __STR(X) +- +- __asm__ __volatile__ ( +- "\tljmp $"STR(__KERNEL_CS)",$1f\n" +- "\t1:\n" +- "\tmovl $"STR(__KERNEL_DS)",%%eax\n" +- "\tmovl %%eax,%%ds\n" +- "\tmovl %%eax,%%es\n" +- "\tmovl %%eax,%%fs\n" +- "\tmovl %%eax,%%gs\n" +- "\tmovl %%eax,%%ss\n" +- ::: "eax", "memory"); +-#undef STR +-#undef __STR +-} +- + /* + * A architecture hook called to validate the + * proposed image and prepare the control pages +@@ -127,23 +85,6 @@ NORET_TYPE void machine_kexec(struct kim + page_list[PA_PTE_1] = __pa(kexec_pte1); + page_list[VA_PTE_1] = (unsigned long)kexec_pte1; + +- /* The segment registers are funny things, they have both a +- * visible and an invisible part. Whenever the visible part is +- * set to a specific selector, the invisible part is loaded +- * with from a table in memory. At no other time is the +- * descriptor table in memory accessed. +- * +- * I take advantage of this here by force loading the +- * segments, before I zap the gdt with an invalid value. +- */ +- load_segments(); +- /* The gdt & idt are now invalid. +- * If you want to load them you must set up your own idt & gdt. +- */ +- set_gdt(phys_to_virt(0),0); +- set_idt(phys_to_virt(0),0); +- +- /* now call it */ + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start, cpu_has_pae); + } +--- 0002/arch/i386/kernel/relocate_kernel.S ++++ work/arch/i386/kernel/relocate_kernel.S 2006-10-05 16:03:21.000000000 +0900 +@@ -154,14 +154,45 @@ relocate_new_kernel: + movl PTR(PA_PGD)(%ebp), %eax + movl %eax, %cr3 + ++ /* setup idt */ ++ movl %edi, %eax ++ addl $(idt_48 - relocate_kernel), %eax ++ lidtl (%eax) ++ ++ /* setup gdt */ ++ movl %edi, %eax ++ addl $(gdt - relocate_kernel), %eax ++ movl %edi, %esi ++ addl $((gdt_48 - relocate_kernel) + 2), %esi ++ movl %eax, (%esi) ++ ++ movl %edi, %eax ++ addl $(gdt_48 - relocate_kernel), %eax ++ lgdtl (%eax) ++ ++ /* setup data segment registers */ ++ mov $(gdt_ds - gdt), %eax ++ mov %eax, %ds ++ mov %eax, %es ++ mov %eax, %fs ++ mov %eax, %gs ++ mov %eax, %ss ++ + /* setup a new stack at the end of the physical control page */ + lea 4096(%edi), %esp + +- /* jump to identity mapped page */ +- movl %edi, %eax +- addl $(identity_mapped - relocate_kernel), %eax +- pushl %eax +- ret ++ /* load new code segment and jump to identity mapped page */ ++ movl %edi, %esi ++ xorl %eax, %eax ++ pushl %eax ++ pushl %esi ++ pushl %eax ++ movl $(gdt_cs - gdt), %eax ++ pushl %eax ++ movl %edi, %eax ++ addl $(identity_mapped - relocate_kernel),%eax ++ pushl %eax ++ iretl + + identity_mapped: + /* store the start address on the stack */ +@@ -250,3 +281,20 @@ identity_mapped: + xorl %edi, %edi + xorl %ebp, %ebp + ret ++ ++ .align 16 ++gdt: ++ .quad 0x0000000000000000 /* NULL descriptor */ ++gdt_cs: ++ .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ ++gdt_ds: ++ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ ++gdt_end: ++ ++gdt_48: ++ .word gdt_end - gdt - 1 /* limit */ ++ .long 0 /* base - filled in by code above */ ++ ++idt_48: ++ .word 0 /* limit */ ++ .long 0 /* base */ diff --git a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch new file mode 100644 index 0000000000..93480f9528 --- /dev/null +++ b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch @@ -0,0 +1,108 @@ +--- 0001/arch/i386/kernel/crash.c ++++ work/arch/i386/kernel/crash.c +@@ -90,6 +90,7 @@ static void crash_save_self(struct pt_re + crash_save_this_cpu(regs, cpu); + } + ++#ifndef CONFIG_XEN + #ifdef CONFIG_SMP + static atomic_t waiting_for_crash_ipi; + +@@ -158,6 +159,7 @@ static void nmi_shootdown_cpus(void) + /* There are no cpus to shootdown */ + } + #endif ++#endif /* CONFIG_XEN */ + + void machine_crash_shutdown(struct pt_regs *regs) + { +@@ -174,10 +176,12 @@ void machine_crash_shutdown(struct pt_re + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = smp_processor_id(); ++#ifndef CONFIG_XEN + nmi_shootdown_cpus(); + lapic_shutdown(); + #if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); + #endif ++#endif /* CONFIG_XEN */ + crash_save_self(regs); + } +--- 0007/arch/i386/kernel/machine_kexec.c ++++ work/arch/i386/kernel/machine_kexec.c +@@ -19,6 +19,10 @@ + #include + #include + ++#ifdef CONFIG_XEN ++#include ++#endif ++ + #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) + static u32 kexec_pgd[1024] PAGE_ALIGNED; + #ifdef CONFIG_X86_PAE +@@ -28,6 +32,40 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED + static u32 kexec_pte0[1024] PAGE_ALIGNED; + static u32 kexec_pte1[1024] PAGE_ALIGNED; + ++#ifdef CONFIG_XEN ++ ++#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) ++ ++#if PAGES_NR > KEXEC_XEN_NO_PAGES ++#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break ++#endif ++ ++#if PA_CONTROL_PAGE != 0 ++#error PA_CONTROL_PAGE is non zero - Xen support will break ++#endif ++ ++void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) ++{ ++ void *control_page; ++ ++ memset(xki->page_list, 0, sizeof(xki->page_list)); ++ ++ control_page = page_address(image->control_code_page); ++ memcpy(control_page, relocate_kernel, PAGE_SIZE); ++ ++ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); ++ xki->page_list[PA_PGD] = __ma(kexec_pgd); ++#ifdef CONFIG_X86_PAE ++ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); ++ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); ++#endif ++ xki->page_list[PA_PTE_0] = __ma(kexec_pte0); ++ xki->page_list[PA_PTE_1] = __ma(kexec_pte1); ++ ++} ++ ++#endif /* CONFIG_XEN */ ++ + /* + * A architecture hook called to validate the + * proposed image and prepare the control pages +--- 0006/include/asm-i386/kexec.h ++++ work/include/asm-i386/kexec.h +@@ -98,6 +98,20 @@ relocate_kernel(unsigned long indirectio + unsigned long start_address, + unsigned int has_pae) ATTRIB_NORET; + ++ ++/* Under Xen we need to work with machine addresses. These macros give the ++ * machine address of a certain page to the generic kexec code instead of ++ * the pseudo physical address which would be given by the default macros. ++ */ ++ ++#ifdef CONFIG_XEN ++#define KEXEC_ARCH_HAS_PAGE_MACROS ++#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) ++#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) ++#define kexec_virt_to_phys(addr) virt_to_machine(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _I386_KEXEC_H */ diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index 025a7be77d..780b7a3499 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -1,6 +1,9 @@ kexec-generic.patch git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch +git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch +linux-2.6.19-rc1-kexec-move_segment_code-i386.patch +linux-2.6.19-rc1-kexec-xen-i386.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 0e26f46497..566f4d4279 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -659,6 +659,7 @@ ENTRY(hypercall_table) .long do_hvm_op .long do_sysctl /* 35 */ .long do_domctl + .long do_kexec_op .rept NR_hypercalls-((.-hypercall_table)/4) .long do_ni_hypercall .endr @@ -701,6 +702,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_hvm_op */ .byte 1 /* do_sysctl */ /* 35 */ .byte 1 /* do_domctl */ + .byte 2 /* do_kexec_op */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff --git a/xen/include/asm-x86/x86_32/elf.h b/xen/include/asm-x86/x86_32/elf.h index 982906cace..a70bd223f2 100644 --- a/xen/include/asm-x86/x86_32/elf.h +++ b/xen/include/asm-x86/x86_32/elf.h @@ -1,16 +1,62 @@ #ifndef __X86_32_ELF_H__ #define __X86_32_ELF_H__ -#include /* for printk() used in stub */ +#include typedef struct { - unsigned long dummy; + unsigned long ebx; + unsigned long ecx; + unsigned long edx; + unsigned long esi; + unsigned long edi; + unsigned long ebp; + unsigned long eax; + unsigned long ds; + unsigned long es; + unsigned long fs; + unsigned long gs; + unsigned long orig_eax; + unsigned long eip; + unsigned long cs; + unsigned long eflags; + unsigned long esp; + unsigned long ss; } ELF_Gregset; extern inline void elf_core_save_regs(ELF_Gregset *core_regs, crash_xen_core_t *xen_core_regs) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + unsigned long tmp; + + asm volatile("movl %%ebx,%0" : "=m"(core_regs->ebx)); + asm volatile("movl %%ecx,%0" : "=m"(core_regs->ecx)); + asm volatile("movl %%edx,%0" : "=m"(core_regs->edx)); + asm volatile("movl %%esi,%0" : "=m"(core_regs->esi)); + asm volatile("movl %%edi,%0" : "=m"(core_regs->edi)); + asm volatile("movl %%ebp,%0" : "=m"(core_regs->ebp)); + asm volatile("movl %%eax,%0" : "=m"(core_regs->eax)); + asm volatile("movw %%ds, %%ax;" :"=a"(core_regs->ds)); + asm volatile("movw %%es, %%ax;" :"=a"(core_regs->es)); + asm volatile("movw %%fs, %%ax;" :"=a"(core_regs->fs)); + asm volatile("movw %%gs, %%ax;" :"=a"(core_regs->gs)); + /* orig_eax not filled in for now */ + core_regs->eip = (unsigned long)current_text_addr(); + asm volatile("movw %%cs, %%ax;" :"=a"(core_regs->cs)); + asm volatile("pushfl; popl %0" :"=m"(core_regs->eflags)); + asm volatile("movl %%esp,%0" : "=m"(core_regs->esp)); + asm volatile("movw %%ss, %%ax;" :"=a"(core_regs->ss)); + + asm volatile("mov %%cr0, %0" : "=r" (tmp) : ); + xen_core_regs->cr0 = tmp; + + asm volatile("mov %%cr2, %0" : "=r" (tmp) : ); + xen_core_regs->cr2 = tmp; + + asm volatile("mov %%cr3, %0" : "=r" (tmp) : ); + xen_core_regs->cr3 = tmp; + + asm volatile("mov %%cr4, %0" : "=r" (tmp) : ); + xen_core_regs->cr4 = tmp; } #endif /* __X86_32_ELF_H__ */ diff --git a/xen/include/asm-x86/x86_32/kexec.h b/xen/include/asm-x86/x86_32/kexec.h index 97bbab8bb2..aa6db02088 100644 --- a/xen/include/asm-x86/x86_32/kexec.h +++ b/xen/include/asm-x86/x86_32/kexec.h @@ -1,17 +1,33 @@ -#ifndef __X86_32_KEXEC_H__ -#define __X86_32_KEXEC_H__ +/****************************************************************************** + * kexec.h + * + * Based heavily on machine_kexec.c and kexec.h from Linux 2.6.19-rc1 + * + */ + +#ifndef __X86_KEXEC_X86_32_H__ +#define __X86_KEXEC_X86_32_H__ -#include /* for printk() used in stub */ #include -#include #include +#include + +typedef asmlinkage void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long page_list, + unsigned long start_address, + unsigned int has_pae); static inline void machine_kexec(xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + relocate_new_kernel_t rnk; + + rnk = (relocate_new_kernel_t) image->page_list[1]; + (*rnk)(image->indirection_page, (unsigned long)image->page_list, + image->start_address, (unsigned long)cpu_has_pae); } -#endif /* __X86_32_KEXEC_H__ */ +#endif /* __X86_KEXEC_X86_32_H__ */ /* * Local variables: From 6fc8621b96e18503bf92a3b1651f35bf17af41a2 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:38:51 +0000 Subject: [PATCH 072/282] [XEN] Kexec / Kdump: x86_64 specific code This patch contains the x86_64 implementation of Kexec / Kdump for Xen. Signed-Off-By: Magnus Damm Signed-Off-By: Simon Horman --- buildconfigs/linux-defconfig_xen_x86_64 | 1 + linux-2.6-xen-sparse/arch/x86_64/Kconfig | 2 +- .../arch/x86_64/kernel/e820-xen.c | 6 +- .../arch/x86_64/kernel/setup-xen.c | 13 + .../asm-x86_64/mach-xen/asm/hypercall.h | 7 + .../include/asm-x86_64/mach-xen/asm/ptrace.h | 2 + ...aef01a1badb9e8ffb0c0a37cd2379008d21f.patch | 375 ++++++++++++++++++ ...9-rc1-kexec-move_segment_code-x86_64.patch | 161 ++++++++ .../linux-2.6.19-rc1-kexec-xen-x86_64.patch | 219 ++++++++++ patches/linux-2.6.16.33/series | 3 + xen/arch/x86/x86_64/entry.S | 2 + xen/include/asm-x86/x86_64/elf.h | 72 +++- xen/include/asm-x86/x86_64/kexec.h | 23 +- 13 files changed, 877 insertions(+), 9 deletions(-) create mode 100644 patches/linux-2.6.16.33/git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch create mode 100644 patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch create mode 100644 patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch diff --git a/buildconfigs/linux-defconfig_xen_x86_64 b/buildconfigs/linux-defconfig_xen_x86_64 index 3f9599adb0..0bca78b24f 100644 --- a/buildconfigs/linux-defconfig_xen_x86_64 +++ b/buildconfigs/linux-defconfig_xen_x86_64 @@ -139,6 +139,7 @@ CONFIG_SWIOTLB=y CONFIG_PHYSICAL_START=0x100000 CONFIG_SECCOMP=y CONFIG_HZ_100=y +CONFIG_KEXEC=y # CONFIG_HZ_250 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 diff --git a/linux-2.6-xen-sparse/arch/x86_64/Kconfig b/linux-2.6-xen-sparse/arch/x86_64/Kconfig index 79bd0044fa..5fcf581612 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/Kconfig +++ b/linux-2.6-xen-sparse/arch/x86_64/Kconfig @@ -435,7 +435,7 @@ config X86_MCE_AMD config KEXEC bool "kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL && !X86_64_XEN + depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/e820-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/e820-xen.c index 333a9a26f4..37427e6285 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/e820-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/e820-xen.c @@ -260,7 +260,11 @@ void __init e820_reserve_resources(struct e820entry *e820, int nr_map) request_resource(res, &data_resource); #endif #ifdef CONFIG_KEXEC - request_resource(res, &crashk_res); + if (crashk_res.start != crashk_res.end) + request_resource(res, &crashk_res); +#ifdef CONFIG_XEN + xen_machine_kexec_register_resources(res); +#endif #endif } } diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c index 711ce5d198..5c630cac9e 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c @@ -80,6 +80,10 @@ #include #include +#ifdef CONFIG_XEN +#include +#endif + extern unsigned long start_pfn; extern struct edid_info edid_info; @@ -450,6 +454,7 @@ static __init void parse_cmdline_early (char ** cmdline_p) * after a kernel panic. */ else if (!memcmp(from, "crashkernel=", 12)) { +#ifndef CONFIG_XEN unsigned long size, base; size = memparse(from+12, &from); if (*from == '@') { @@ -460,6 +465,10 @@ static __init void parse_cmdline_early (char ** cmdline_p) crashk_res.start = base; crashk_res.end = base + size - 1; } +#else + printk("Ignoring crashkernel command line, " + "parameter will be supplied by xen\n"); +#endif } #endif @@ -812,10 +821,14 @@ void __init setup_arch(char **cmdline_p) #endif #endif /* !CONFIG_XEN */ #ifdef CONFIG_KEXEC +#ifdef CONFIG_XEN + xen_machine_kexec_setup_resources(); +#else if (crashk_res.start != crashk_res.end) { reserve_bootmem(crashk_res.start, crashk_res.end - crashk_res.start + 1); } +#endif #endif paging_init(); diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h index 956a4c4b0d..5c6c8deff6 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/hypercall.h @@ -396,4 +396,11 @@ HYPERVISOR_xenoprof_op( return _hypercall2(int, xenoprof_op, op, arg); } +static inline int +HYPERVISOR_kexec_op( + unsigned long op, void *args) +{ + return _hypercall2(int, kexec_op, op, args); +} + #endif /* __HYPERCALL_H__ */ diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h index 052f05bca8..e6801fa7af 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/ptrace.h @@ -90,6 +90,8 @@ extern unsigned long profile_pc(struct pt_regs *regs); #define profile_pc(regs) instruction_pointer(regs) #endif +#include + void signal_fault(struct pt_regs *regs, void __user *frame, char *where); struct task_struct; diff --git a/patches/linux-2.6.16.33/git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch b/patches/linux-2.6.16.33/git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch new file mode 100644 index 0000000000..6e1f65fe9f --- /dev/null +++ b/patches/linux-2.6.16.33/git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch @@ -0,0 +1,375 @@ +From: Magnus Damm +Date: Tue, 26 Sep 2006 08:52:38 +0000 (+0200) +Subject: [PATCH] Avoid overwriting the current pgd (V4, x86_64) +X-Git-Tag: v2.6.19-rc1 +X-Git-Url: http://www.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f + +[PATCH] Avoid overwriting the current pgd (V4, x86_64) + +kexec: Avoid overwriting the current pgd (V4, x86_64) + +This patch upgrades the x86_64-specific kexec code to avoid overwriting the +current pgd. Overwriting the current pgd is bad when CONFIG_CRASH_DUMP is used +to start a secondary kernel that dumps the memory of the previous kernel. + +The code introduces a new set of page tables. These tables are used to provide +an executable identity mapping without overwriting the current pgd. + +Signed-off-by: Magnus Damm +Signed-off-by: Andi Kleen +--- + +--- a/arch/x86_64/kernel/machine_kexec.c ++++ b/arch/x86_64/kernel/machine_kexec.c +@@ -15,6 +15,15 @@ + #include + #include + ++#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) ++static u64 kexec_pgd[512] PAGE_ALIGNED; ++static u64 kexec_pud0[512] PAGE_ALIGNED; ++static u64 kexec_pmd0[512] PAGE_ALIGNED; ++static u64 kexec_pte0[512] PAGE_ALIGNED; ++static u64 kexec_pud1[512] PAGE_ALIGNED; ++static u64 kexec_pmd1[512] PAGE_ALIGNED; ++static u64 kexec_pte1[512] PAGE_ALIGNED; ++ + static void init_level2_page(pmd_t *level2p, unsigned long addr) + { + unsigned long end_addr; +@@ -144,32 +153,19 @@ static void load_segments(void) + ); + } + +-typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page, +- unsigned long control_code_buffer, +- unsigned long start_address, +- unsigned long pgtable) ATTRIB_NORET; +- +-extern const unsigned char relocate_new_kernel[]; +-extern const unsigned long relocate_new_kernel_size; +- + int machine_kexec_prepare(struct kimage *image) + { +- unsigned long start_pgtable, control_code_buffer; ++ unsigned long start_pgtable; + int result; + + /* Calculate the offsets */ + start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; +- control_code_buffer = start_pgtable + PAGE_SIZE; + + /* Setup the identity mapped 64bit page table */ + result = init_pgtable(image, start_pgtable); + if (result) + return result; + +- /* Place the code in the reboot code buffer */ +- memcpy(__va(control_code_buffer), relocate_new_kernel, +- relocate_new_kernel_size); +- + return 0; + } + +@@ -184,28 +180,34 @@ void machine_kexec_cleanup(struct kimage + */ + NORET_TYPE void machine_kexec(struct kimage *image) + { +- unsigned long page_list; +- unsigned long control_code_buffer; +- unsigned long start_pgtable; +- relocate_new_kernel_t rnk; ++ unsigned long page_list[PAGES_NR]; ++ void *control_page; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + +- /* Calculate the offsets */ +- page_list = image->head; +- start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; +- control_code_buffer = start_pgtable + PAGE_SIZE; ++ control_page = page_address(image->control_code_page) + PAGE_SIZE; ++ memcpy(control_page, relocate_kernel, PAGE_SIZE); + +- /* Set the low half of the page table to my identity mapped +- * page table for kexec. Leave the high half pointing at the +- * kernel pages. Don't bother to flush the global pages +- * as that will happen when I fully switch to my identity mapped +- * page table anyway. +- */ +- memcpy(__va(read_cr3()), __va(start_pgtable), PAGE_SIZE/2); +- __flush_tlb(); ++ page_list[PA_CONTROL_PAGE] = __pa(control_page); ++ page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; ++ page_list[PA_PGD] = __pa(kexec_pgd); ++ page_list[VA_PGD] = (unsigned long)kexec_pgd; ++ page_list[PA_PUD_0] = __pa(kexec_pud0); ++ page_list[VA_PUD_0] = (unsigned long)kexec_pud0; ++ page_list[PA_PMD_0] = __pa(kexec_pmd0); ++ page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; ++ page_list[PA_PTE_0] = __pa(kexec_pte0); ++ page_list[VA_PTE_0] = (unsigned long)kexec_pte0; ++ page_list[PA_PUD_1] = __pa(kexec_pud1); ++ page_list[VA_PUD_1] = (unsigned long)kexec_pud1; ++ page_list[PA_PMD_1] = __pa(kexec_pmd1); ++ page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; ++ page_list[PA_PTE_1] = __pa(kexec_pte1); ++ page_list[VA_PTE_1] = (unsigned long)kexec_pte1; + ++ page_list[PA_TABLE_PAGE] = ++ (unsigned long)__pa(page_address(image->control_code_page)); + + /* The segment registers are funny things, they have both a + * visible and an invisible part. Whenever the visible part is +@@ -222,9 +224,10 @@ NORET_TYPE void machine_kexec(struct kim + */ + set_gdt(phys_to_virt(0),0); + set_idt(phys_to_virt(0),0); ++ + /* now call it */ +- rnk = (relocate_new_kernel_t) control_code_buffer; +- (*rnk)(page_list, control_code_buffer, image->start, start_pgtable); ++ relocate_kernel((unsigned long)image->head, (unsigned long)page_list, ++ image->start); + } + + /* crashkernel=size@addr specifies the location to reserve for +--- a/arch/x86_64/kernel/relocate_kernel.S ++++ b/arch/x86_64/kernel/relocate_kernel.S +@@ -7,31 +7,169 @@ + */ + + #include ++#include ++#include + +- /* +- * Must be relocatable PIC code callable as a C function, that once +- * it starts can not use the previous processes stack. +- */ +- .globl relocate_new_kernel ++/* ++ * Must be relocatable PIC code callable as a C function ++ */ ++ ++#define PTR(x) (x << 3) ++#define PAGE_ALIGNED (1 << PAGE_SHIFT) ++#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */ ++ ++ .text ++ .align PAGE_ALIGNED + .code64 ++ .globl relocate_kernel ++relocate_kernel: ++ /* %rdi indirection_page ++ * %rsi page_list ++ * %rdx start address ++ */ ++ ++ /* map the control page at its virtual address */ ++ ++ movq $0x0000ff8000000000, %r10 /* mask */ ++ mov $(39 - 3), %cl /* bits to shift */ ++ movq PTR(VA_CONTROL_PAGE)(%rsi), %r11 /* address to map */ ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PGD)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_PUD_0)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ shrq $9, %r10 ++ sub $9, %cl ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PUD_0)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_PMD_0)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ shrq $9, %r10 ++ sub $9, %cl ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PMD_0)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_PTE_0)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ shrq $9, %r10 ++ sub $9, %cl ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PTE_0)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ /* identity map the control page at its physical address */ ++ ++ movq $0x0000ff8000000000, %r10 /* mask */ ++ mov $(39 - 3), %cl /* bits to shift */ ++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r11 /* address to map */ ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PGD)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_PUD_1)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ shrq $9, %r10 ++ sub $9, %cl ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PUD_1)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_PMD_1)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ shrq $9, %r10 ++ sub $9, %cl ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PMD_1)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_PTE_1)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ ++ shrq $9, %r10 ++ sub $9, %cl ++ ++ movq %r11, %r9 ++ andq %r10, %r9 ++ shrq %cl, %r9 ++ ++ movq PTR(VA_PTE_1)(%rsi), %r8 ++ addq %r8, %r9 ++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 ++ orq $PAGE_ATTR, %r8 ++ movq %r8, (%r9) ++ + relocate_new_kernel: +- /* %rdi page_list +- * %rsi reboot_code_buffer ++ /* %rdi indirection_page ++ * %rsi page_list + * %rdx start address +- * %rcx page_table +- * %r8 arg5 +- * %r9 arg6 + */ + + /* zero out flags, and disable interrupts */ + pushq $0 + popfq + +- /* set a new stack at the bottom of our page... */ +- lea 4096(%rsi), %rsp ++ /* get physical address of control page now */ ++ /* this is impossible after page table switch */ ++ movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 ++ ++ /* get physical address of page table now too */ ++ movq PTR(PA_TABLE_PAGE)(%rsi), %rcx ++ ++ /* switch to new set of page tables */ ++ movq PTR(PA_PGD)(%rsi), %r9 ++ movq %r9, %cr3 ++ ++ /* setup a new stack at the end of the physical control page */ ++ lea 4096(%r8), %rsp ++ ++ /* jump to identity mapped page */ ++ addq $(identity_mapped - relocate_kernel), %r8 ++ pushq %r8 ++ ret + +- /* store the parameters back on the stack */ +- pushq %rdx /* store the start address */ ++identity_mapped: ++ /* store the start address on the stack */ ++ pushq %rdx + + /* Set cr0 to a known state: + * 31 1 == Paging enabled +@@ -136,8 +274,3 @@ relocate_new_kernel: + xorq %r15, %r15 + + ret +-relocate_new_kernel_end: +- +- .globl relocate_new_kernel_size +-relocate_new_kernel_size: +- .quad relocate_new_kernel_end - relocate_new_kernel +--- a/include/asm-x86_64/kexec.h ++++ b/include/asm-x86_64/kexec.h +@@ -1,6 +1,27 @@ + #ifndef _X86_64_KEXEC_H + #define _X86_64_KEXEC_H + ++#define PA_CONTROL_PAGE 0 ++#define VA_CONTROL_PAGE 1 ++#define PA_PGD 2 ++#define VA_PGD 3 ++#define PA_PUD_0 4 ++#define VA_PUD_0 5 ++#define PA_PMD_0 6 ++#define VA_PMD_0 7 ++#define PA_PTE_0 8 ++#define VA_PTE_0 9 ++#define PA_PUD_1 10 ++#define VA_PUD_1 11 ++#define PA_PMD_1 12 ++#define VA_PMD_1 13 ++#define PA_PTE_1 14 ++#define VA_PTE_1 15 ++#define PA_TABLE_PAGE 16 ++#define PAGES_NR 17 ++ ++#ifndef __ASSEMBLY__ ++ + #include + + #include +@@ -64,4 +85,12 @@ static inline void crash_setup_regs(stru + newregs->rip = (unsigned long)current_text_addr(); + } + } ++ ++NORET_TYPE void ++relocate_kernel(unsigned long indirection_page, ++ unsigned long page_list, ++ unsigned long start_address) ATTRIB_NORET; ++ ++#endif /* __ASSEMBLY__ */ ++ + #endif /* _X86_64_KEXEC_H */ diff --git a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch new file mode 100644 index 0000000000..1cf613284f --- /dev/null +++ b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch @@ -0,0 +1,161 @@ +kexec: Move asm segment handling code to the assembly file (x86_64) + +This patch moves the idt, gdt, and segment handling code from machine_kexec.c +to relocate_kernel.S. The main reason behind this move is to avoid code +duplication in the Xen hypervisor. With this patch all code required to kexec +is put on the control page. + +On top of that this patch also counts as a cleanup - I think it is much +nicer to write assembly directly in assembly files than wrap inline assembly +in C functions for no apparent reason. + +Signed-off-by: Magnus Damm +--- + + Applies to 2.6.19-rc1. + + machine_kexec.c | 58 ----------------------------------------------------- + relocate_kernel.S | 50 +++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 45 insertions(+), 63 deletions(-) + +--- 0002/arch/x86_64/kernel/machine_kexec.c ++++ work/arch/x86_64/kernel/machine_kexec.c 2006-10-05 16:15:49.000000000 +0900 +@@ -112,47 +112,6 @@ static int init_pgtable(struct kimage *i + return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); + } + +-static void set_idt(void *newidt, u16 limit) +-{ +- struct desc_ptr curidt; +- +- /* x86-64 supports unaliged loads & stores */ +- curidt.size = limit; +- curidt.address = (unsigned long)newidt; +- +- __asm__ __volatile__ ( +- "lidtq %0\n" +- : : "m" (curidt) +- ); +-}; +- +- +-static void set_gdt(void *newgdt, u16 limit) +-{ +- struct desc_ptr curgdt; +- +- /* x86-64 supports unaligned loads & stores */ +- curgdt.size = limit; +- curgdt.address = (unsigned long)newgdt; +- +- __asm__ __volatile__ ( +- "lgdtq %0\n" +- : : "m" (curgdt) +- ); +-}; +- +-static void load_segments(void) +-{ +- __asm__ __volatile__ ( +- "\tmovl %0,%%ds\n" +- "\tmovl %0,%%es\n" +- "\tmovl %0,%%ss\n" +- "\tmovl %0,%%fs\n" +- "\tmovl %0,%%gs\n" +- : : "a" (__KERNEL_DS) : "memory" +- ); +-} +- + int machine_kexec_prepare(struct kimage *image) + { + unsigned long start_pgtable; +@@ -209,23 +168,6 @@ NORET_TYPE void machine_kexec(struct kim + page_list[PA_TABLE_PAGE] = + (unsigned long)__pa(page_address(image->control_code_page)); + +- /* The segment registers are funny things, they have both a +- * visible and an invisible part. Whenever the visible part is +- * set to a specific selector, the invisible part is loaded +- * with from a table in memory. At no other time is the +- * descriptor table in memory accessed. +- * +- * I take advantage of this here by force loading the +- * segments, before I zap the gdt with an invalid value. +- */ +- load_segments(); +- /* The gdt & idt are now invalid. +- * If you want to load them you must set up your own idt & gdt. +- */ +- set_gdt(phys_to_virt(0),0); +- set_idt(phys_to_virt(0),0); +- +- /* now call it */ + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start); + } +--- 0002/arch/x86_64/kernel/relocate_kernel.S ++++ work/arch/x86_64/kernel/relocate_kernel.S 2006-10-05 16:18:07.000000000 +0900 +@@ -159,13 +159,39 @@ relocate_new_kernel: + movq PTR(PA_PGD)(%rsi), %r9 + movq %r9, %cr3 + ++ /* setup idt */ ++ movq %r8, %rax ++ addq $(idt_80 - relocate_kernel), %rax ++ lidtq (%rax) ++ ++ /* setup gdt */ ++ movq %r8, %rax ++ addq $(gdt - relocate_kernel), %rax ++ movq %r8, %r9 ++ addq $((gdt_80 - relocate_kernel) + 2), %r9 ++ movq %rax, (%r9) ++ ++ movq %r8, %rax ++ addq $(gdt_80 - relocate_kernel), %rax ++ lgdtq (%rax) ++ ++ /* setup data segment registers */ ++ xorl %eax, %eax ++ movl %eax, %ds ++ movl %eax, %es ++ movl %eax, %fs ++ movl %eax, %gs ++ movl %eax, %ss ++ + /* setup a new stack at the end of the physical control page */ + lea 4096(%r8), %rsp + +- /* jump to identity mapped page */ +- addq $(identity_mapped - relocate_kernel), %r8 +- pushq %r8 +- ret ++ /* load new code segment and jump to identity mapped page */ ++ movq %r8, %rax ++ addq $(identity_mapped - relocate_kernel), %rax ++ pushq $(gdt_cs - gdt) ++ pushq %rax ++ lretq + + identity_mapped: + /* store the start address on the stack */ +@@ -272,5 +298,19 @@ identity_mapped: + xorq %r13, %r13 + xorq %r14, %r14 + xorq %r15, %r15 +- + ret ++ ++ .align 16 ++gdt: ++ .quad 0x0000000000000000 /* NULL descriptor */ ++gdt_cs: ++ .quad 0x00af9a000000ffff ++gdt_end: ++ ++gdt_80: ++ .word gdt_end - gdt - 1 /* limit */ ++ .quad 0 /* base - filled in by code above */ ++ ++idt_80: ++ .word 0 /* limit */ ++ .quad 0 /* base */ diff --git a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch new file mode 100644 index 0000000000..c387519889 --- /dev/null +++ b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch @@ -0,0 +1,219 @@ +--- 0001/arch/x86_64/kernel/crash.c ++++ work/arch/x86_64/kernel/crash.c +@@ -92,6 +92,7 @@ static void crash_save_self(struct pt_re + crash_save_this_cpu(regs, cpu); + } + ++#ifndef CONFIG_XEN + #ifdef CONFIG_SMP + static atomic_t waiting_for_crash_ipi; + +@@ -156,6 +157,7 @@ static void nmi_shootdown_cpus(void) + /* There are no cpus to shootdown */ + } + #endif ++#endif /* CONFIG_XEN */ + + void machine_crash_shutdown(struct pt_regs *regs) + { +@@ -173,6 +175,8 @@ void machine_crash_shutdown(struct pt_re + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = smp_processor_id(); ++ ++#ifndef CONFIG_XEN + nmi_shootdown_cpus(); + + if(cpu_has_apic) +@@ -181,6 +185,6 @@ void machine_crash_shutdown(struct pt_re + #if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); + #endif +- ++#endif /* CONFIG_XEN */ + crash_save_self(regs); + } +--- 0010/arch/x86_64/kernel/machine_kexec.c ++++ work/arch/x86_64/kernel/machine_kexec.c +@@ -24,6 +24,104 @@ static u64 kexec_pud1[512] PAGE_ALIGNED; + static u64 kexec_pmd1[512] PAGE_ALIGNED; + static u64 kexec_pte1[512] PAGE_ALIGNED; + ++#ifdef CONFIG_XEN ++ ++/* In the case of Xen, override hypervisor functions to be able to create ++ * a regular identity mapping page table... ++ */ ++ ++#include ++#include ++ ++#define x__pmd(x) ((pmd_t) { (x) } ) ++#define x__pud(x) ((pud_t) { (x) } ) ++#define x__pgd(x) ((pgd_t) { (x) } ) ++ ++#define x_pmd_val(x) ((x).pmd) ++#define x_pud_val(x) ((x).pud) ++#define x_pgd_val(x) ((x).pgd) ++ ++static inline void x_set_pmd(pmd_t *dst, pmd_t val) ++{ ++ x_pmd_val(*dst) = x_pmd_val(val); ++} ++ ++static inline void x_set_pud(pud_t *dst, pud_t val) ++{ ++ x_pud_val(*dst) = phys_to_machine(x_pud_val(val)); ++} ++ ++static inline void x_pud_clear (pud_t *pud) ++{ ++ x_pud_val(*pud) = 0; ++} ++ ++static inline void x_set_pgd(pgd_t *dst, pgd_t val) ++{ ++ x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val)); ++} ++ ++static inline void x_pgd_clear (pgd_t * pgd) ++{ ++ x_pgd_val(*pgd) = 0; ++} ++ ++#define X__PAGE_KERNEL_LARGE_EXEC \ ++ _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE ++#define X_KERNPG_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY ++ ++#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) ++ ++#if PAGES_NR > KEXEC_XEN_NO_PAGES ++#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break ++#endif ++ ++#if PA_CONTROL_PAGE != 0 ++#error PA_CONTROL_PAGE is non zero - Xen support will break ++#endif ++ ++void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) ++{ ++ void *control_page; ++ void *table_page; ++ ++ memset(xki->page_list, 0, sizeof(xki->page_list)); ++ ++ control_page = page_address(image->control_code_page) + PAGE_SIZE; ++ memcpy(control_page, relocate_kernel, PAGE_SIZE); ++ ++ table_page = page_address(image->control_code_page); ++ ++ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); ++ xki->page_list[PA_TABLE_PAGE] = __ma(table_page); ++ ++ xki->page_list[PA_PGD] = __ma(kexec_pgd); ++ xki->page_list[PA_PUD_0] = __ma(kexec_pud0); ++ xki->page_list[PA_PUD_1] = __ma(kexec_pud1); ++ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); ++ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); ++ xki->page_list[PA_PTE_0] = __ma(kexec_pte0); ++ xki->page_list[PA_PTE_1] = __ma(kexec_pte1); ++} ++ ++#else /* CONFIG_XEN */ ++ ++#define x__pmd(x) __pmd(x) ++#define x__pud(x) __pud(x) ++#define x__pgd(x) __pgd(x) ++ ++#define x_set_pmd(x, y) set_pmd(x, y) ++#define x_set_pud(x, y) set_pud(x, y) ++#define x_set_pgd(x, y) set_pgd(x, y) ++ ++#define x_pud_clear(x) pud_clear(x) ++#define x_pgd_clear(x) pgd_clear(x) ++ ++#define X__PAGE_KERNEL_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC ++#define X_KERNPG_TABLE _KERNPG_TABLE ++ ++#endif /* CONFIG_XEN */ ++ + static void init_level2_page(pmd_t *level2p, unsigned long addr) + { + unsigned long end_addr; +@@ -31,7 +129,7 @@ static void init_level2_page(pmd_t *leve + addr &= PAGE_MASK; + end_addr = addr + PUD_SIZE; + while (addr < end_addr) { +- set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC)); ++ x_set_pmd(level2p++, x__pmd(addr | X__PAGE_KERNEL_LARGE_EXEC)); + addr += PMD_SIZE; + } + } +@@ -56,12 +154,12 @@ static int init_level3_page(struct kimag + } + level2p = (pmd_t *)page_address(page); + init_level2_page(level2p, addr); +- set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE)); ++ x_set_pud(level3p++, x__pud(__pa(level2p) | X_KERNPG_TABLE)); + addr += PUD_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { +- pud_clear(level3p++); ++ x_pud_clear(level3p++); + addr += PUD_SIZE; + } + out: +@@ -92,12 +190,12 @@ static int init_level4_page(struct kimag + if (result) { + goto out; + } +- set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE)); ++ x_set_pgd(level4p++, x__pgd(__pa(level3p) | X_KERNPG_TABLE)); + addr += PGDIR_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { +- pgd_clear(level4p++); ++ x_pgd_clear(level4p++); + addr += PGDIR_SIZE; + } + out: +@@ -108,8 +206,14 @@ out: + static int init_pgtable(struct kimage *image, unsigned long start_pgtable) + { + pgd_t *level4p; ++ unsigned long x_end_pfn = end_pfn; ++ ++#ifdef CONFIG_XEN ++ x_end_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); ++#endif ++ + level4p = (pgd_t *)__va(start_pgtable); +- return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); ++ return init_level4_page(image, level4p, 0, x_end_pfn << PAGE_SHIFT); + } + + int machine_kexec_prepare(struct kimage *image) +--- 0009/include/asm-x86_64/kexec.h ++++ work/include/asm-x86_64/kexec.h +@@ -91,6 +91,19 @@ relocate_kernel(unsigned long indirectio + unsigned long page_list, + unsigned long start_address) ATTRIB_NORET; + ++/* Under Xen we need to work with machine addresses. These macros give the ++ * machine address of a certain page to the generic kexec code instead of ++ * the pseudo physical address which would be given by the default macros. ++ */ ++ ++#ifdef CONFIG_XEN ++#define KEXEC_ARCH_HAS_PAGE_MACROS ++#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) ++#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) ++#define kexec_virt_to_phys(addr) virt_to_machine(addr) ++#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) ++#endif ++ + #endif /* __ASSEMBLY__ */ + + #endif /* _X86_64_KEXEC_H */ diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index 780b7a3499..81cc316ad8 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -4,6 +4,9 @@ git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch linux-2.6.19-rc1-kexec-move_segment_code-i386.patch linux-2.6.19-rc1-kexec-xen-i386.patch +git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch +linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch +linux-2.6.19-rc1-kexec-xen-x86_64.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 3f2b8297c7..87602a3d86 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -559,6 +559,7 @@ ENTRY(hypercall_table) .quad do_hvm_op .quad do_sysctl /* 35 */ .quad do_domctl + .quad do_kexec_op .rept NR_hypercalls-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -601,6 +602,7 @@ ENTRY(hypercall_args_table) .byte 2 /* do_hvm_op */ .byte 1 /* do_sysctl */ /* 35 */ .byte 1 /* do_domctl */ + .byte 2 /* do_kexec */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff --git a/xen/include/asm-x86/x86_64/elf.h b/xen/include/asm-x86/x86_64/elf.h index 8068c3ab5d..75f191b43c 100644 --- a/xen/include/asm-x86/x86_64/elf.h +++ b/xen/include/asm-x86/x86_64/elf.h @@ -1,16 +1,82 @@ #ifndef __X86_64_ELF_H__ #define __X86_64_ELF_H__ -#include /* for printk() used in stub */ +#include typedef struct { - unsigned long dummy; + unsigned long r15; + unsigned long r14; + unsigned long r13; + unsigned long r12; + unsigned long rbp; + unsigned long rbx; + unsigned long r11; + unsigned long r10; + unsigned long r9; + unsigned long r8; + unsigned long rax; + unsigned long rcx; + unsigned long rdx; + unsigned long rsi; + unsigned long rdi; + unsigned long orig_rax; + unsigned long rip; + unsigned long cs; + unsigned long eflags; + unsigned long rsp; + unsigned long ss; + unsigned long thread_fs; + unsigned long thread_gs; + unsigned long ds; + unsigned long es; + unsigned long fs; + unsigned long gs; } ELF_Gregset; extern inline void elf_core_save_regs(ELF_Gregset *core_regs, crash_xen_core_t *xen_core_regs) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + unsigned long tmp; + + asm volatile("movq %%r15,%0" : "=m"(core_regs->r15)); + asm volatile("movq %%r14,%0" : "=m"(core_regs->r14)); + asm volatile("movq %%r13,%0" : "=m"(core_regs->r13)); + asm volatile("movq %%r12,%0" : "=m"(core_regs->r12)); + asm volatile("movq %%rbp,%0" : "=m"(core_regs->rbp)); + asm volatile("movq %%rbx,%0" : "=m"(core_regs->rbx)); + asm volatile("movq %%r11,%0" : "=m"(core_regs->r11)); + asm volatile("movq %%r10,%0" : "=m"(core_regs->r10)); + asm volatile("movq %%r9,%0" : "=m"(core_regs->r9)); + asm volatile("movq %%r8,%0" : "=m"(core_regs->r8)); + asm volatile("movq %%rax,%0" : "=m"(core_regs->rax)); + asm volatile("movq %%rcx,%0" : "=m"(core_regs->rcx)); + asm volatile("movq %%rdx,%0" : "=m"(core_regs->rdx)); + asm volatile("movq %%rsi,%0" : "=m"(core_regs->rsi)); + asm volatile("movq %%rdi,%0" : "=m"(core_regs->rdi)); + /* orig_rax not filled in for now */ + core_regs->rip = (unsigned long)current_text_addr(); + asm volatile("movl %%cs, %%eax;" :"=a"(core_regs->cs)); + asm volatile("pushfq; popq %0" :"=m"(core_regs->eflags)); + asm volatile("movq %%rsp,%0" : "=m"(core_regs->rsp)); + asm volatile("movl %%ss, %%eax;" :"=a"(core_regs->ss)); + /* thread_fs not filled in for now */ + /* thread_gs not filled in for now */ + asm volatile("movl %%ds, %%eax;" :"=a"(core_regs->ds)); + asm volatile("movl %%es, %%eax;" :"=a"(core_regs->es)); + asm volatile("movl %%fs, %%eax;" :"=a"(core_regs->fs)); + asm volatile("movl %%gs, %%eax;" :"=a"(core_regs->gs)); + + asm volatile("mov %%cr0, %0" : "=r" (tmp) : ); + xen_core_regs->cr0 = tmp; + + asm volatile("mov %%cr2, %0" : "=r" (tmp) : ); + xen_core_regs->cr2 = tmp; + + asm volatile("mov %%cr3, %0" : "=r" (tmp) : ); + xen_core_regs->cr3 = tmp; + + asm volatile("mov %%cr4, %0" : "=r" (tmp) : ); + xen_core_regs->cr4 = tmp; } #endif /* __X86_64_ELF_H__ */ diff --git a/xen/include/asm-x86/x86_64/kexec.h b/xen/include/asm-x86/x86_64/kexec.h index 3433ba7846..b9779aa9d7 100644 --- a/xen/include/asm-x86/x86_64/kexec.h +++ b/xen/include/asm-x86/x86_64/kexec.h @@ -1,14 +1,29 @@ +/****************************************************************************** + * kexec.h + * + * Based heavily on machine_kexec.c and kexec.h from Linux 2.6.19-rc1 + * + */ + #ifndef __X86_64_KEXEC_H__ #define __X86_64_KEXEC_H__ - -#include /* for printk() used in stub */ + #include -#include #include +#include + +typedef void (*relocate_new_kernel_t)( + unsigned long indirection_page, + unsigned long page_list, + unsigned long start_address); static inline void machine_kexec(xen_kexec_image_t *image) { - printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); + relocate_new_kernel_t rnk; + + rnk = (relocate_new_kernel_t) image->page_list[1]; + (*rnk)(image->indirection_page, (unsigned long)image->page_list, + image->start_address); } #endif /* __X86_64_KEXEC_H__ */ From f8d586356a8cd248443f3fb0f01a53530c8e9b0a Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:38:51 +0000 Subject: [PATCH 073/282] [LINUX] kexec: Backport fix for overlapping program headers in x86_64 linker script. This allows a native kernel built from the xen tree to be used as a crash kernel on x86_64. Signed-off-by: Ian Campbell --- ...b49f92ff6ae6255762a948375e4036cbdbd2.patch | 47 +++++++++++++++++++ patches/linux-2.6.16.33/series | 1 + 2 files changed, 48 insertions(+) create mode 100644 patches/linux-2.6.16.33/git-dbaab49f92ff6ae6255762a948375e4036cbdbd2.patch diff --git a/patches/linux-2.6.16.33/git-dbaab49f92ff6ae6255762a948375e4036cbdbd2.patch b/patches/linux-2.6.16.33/git-dbaab49f92ff6ae6255762a948375e4036cbdbd2.patch new file mode 100644 index 0000000000..199cabd4c9 --- /dev/null +++ b/patches/linux-2.6.16.33/git-dbaab49f92ff6ae6255762a948375e4036cbdbd2.patch @@ -0,0 +1,47 @@ +commit dbaab49f92ff6ae6255762a948375e4036cbdbd2 +Author: Vivek Goyal +Date: Sat Oct 21 18:37:03 2006 +0200 + + [PATCH] x86-64: Overlapping program headers in physical addr space fix + + o A recent change to vmlinux.ld.S file broke kexec as now resulting vmlinux + program headers are overlapping in physical address space. + + o Now all the vsyscall related sections are placed after data and after + that mostly init data sections are placed. To avoid physical overlap + among phdrs, there are three possible solutions. + - Place vsyscall sections also in data phdrs instead of user + - move vsyscal sections after init data in bss. + - create another phdrs say data.init and move all the sections + after vsyscall into this new phdr. + + o This patch implements the third solution. + + Signed-off-by: Vivek Goyal + Signed-off-by: Andi Kleen + Cc: Magnus Damm + Cc: Andi Kleen + Cc: "Eric W. Biederman" + Signed-off-by: Andrew Morton + +diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S +index b9df2ab..1283614 100644 +--- a/arch/x86_64/kernel/vmlinux.lds.S ++++ b/arch/x86_64/kernel/vmlinux.lds.S +@@ -17,6 +17,7 @@ PHDRS { + text PT_LOAD FLAGS(5); /* R_E */ + data PT_LOAD FLAGS(7); /* RWE */ + user PT_LOAD FLAGS(7); /* RWE */ ++ data.init PT_LOAD FLAGS(7); /* RWE */ + note PT_NOTE FLAGS(4); /* R__ */ + } + SECTIONS +@@ -131,7 +132,7 @@ SECTIONS + . = ALIGN(8192); /* init_task */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) +- } :data ++ }:data.init + + . = ALIGN(4096); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index 81cc316ad8..1f01b4033f 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -31,6 +31,7 @@ xen-hotplug.patch xenoprof-generic.patch x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch +git-dbaab49f92ff6ae6255762a948375e4036cbdbd2.patch x86-elfnote-as-preprocessor-macro.patch vsnprintf.patch kasprintf.patch From 432ae399ed924e7104b66b122cb9feaee4c359d7 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:38:51 +0000 Subject: [PATCH 074/282] [XEN] Fixup whitespace and tweak for Xen coding style. Signed-off-by: Ian Campbell --- xen/arch/x86/crash.c | 64 ++++++++++++++++++------------------ xen/arch/x86/machine_kexec.c | 28 ++++++++++------ xen/arch/x86/setup.c | 21 ++++++------ xen/common/kexec.c | 58 ++++++++++++++++---------------- 4 files changed, 90 insertions(+), 81 deletions(-) diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c index 73ed160021..3389174a7a 100644 --- a/xen/arch/x86/crash.c +++ b/xen/arch/x86/crash.c @@ -1,6 +1,6 @@ /****************************************************************************** * crash.c - * + * * Based heavily on arch/i386/kernel/crash.c from Linux 2.6.16 * * Xen port written by: @@ -32,23 +32,23 @@ static atomic_t waiting_for_crash_ipi; static int crash_nmi_callback(struct cpu_user_regs *regs, int cpu) { - /* Don't do anything if this handler is invoked on crashing cpu. - * Otherwise, system will completely hang. Crashing cpu can get - * an NMI if system was initially booted with nmi_watchdog parameter. - */ - if (cpu == crashing_cpu) - return 1; - local_irq_disable(); + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if ( cpu == crashing_cpu ) + return 1; + local_irq_disable(); machine_crash_save_cpu(); - disable_local_APIC(); - atomic_dec(&waiting_for_crash_ipi); - hvm_disable(); + disable_local_APIC(); + atomic_dec(&waiting_for_crash_ipi); + hvm_disable(); for ( ; ; ) __asm__ __volatile__ ( "hlt" ); - return 1; + return 1; } /* @@ -60,31 +60,32 @@ static void smp_send_nmi_allbutself(void) { cpumask_t allbutself = cpu_online_map; - cpu_clear(smp_processor_id(), allbutself); + cpu_clear(smp_processor_id(), allbutself); send_IPI_mask(allbutself, APIC_DM_NMI); } static void nmi_shootdown_cpus(void) { - unsigned long msecs; + unsigned long msecs; - atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); - /* Would it be better to replace the trap vector here? */ - set_nmi_callback(crash_nmi_callback); - /* Ensure the new callback function is set before sending - * out the NMI - */ - wmb(); + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + set_nmi_callback(crash_nmi_callback); + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); - smp_send_nmi_allbutself(); + smp_send_nmi_allbutself(); - msecs = 1000; /* Wait at most a second for the other cpus to stop */ - while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { - mdelay(1); - msecs--; - } + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ( (atomic_read(&waiting_for_crash_ipi) > 0) && msecs ) + { + mdelay(1); + msecs--; + } - /* Leave the nmi callback set */ + /* Leave the nmi callback set */ disable_local_APIC(); } #endif @@ -101,11 +102,11 @@ static void crash_save_xen_notes(void) void machine_crash_shutdown(void) { - printk("machine_crash_shutdown: %d\n", smp_processor_id()); - local_irq_disable(); + printk("machine_crash_shutdown: %d\n", smp_processor_id()); + local_irq_disable(); #ifdef CONFIG_SMP - nmi_shootdown_cpus(); + nmi_shootdown_cpus(); #endif #ifdef CONFIG_X86_IO_APIC @@ -125,4 +126,3 @@ void machine_crash_shutdown(void) * indent-tabs-mode: nil * End: */ - diff --git a/xen/arch/x86/machine_kexec.c b/xen/arch/x86/machine_kexec.c index f60296271d..64a4a3f19f 100644 --- a/xen/arch/x86/machine_kexec.c +++ b/xen/arch/x86/machine_kexec.c @@ -1,6 +1,6 @@ /****************************************************************************** * machine_kexec.c - * + * * Xen port written by: * - Simon 'Horms' Horman * - Magnus Damm @@ -30,23 +30,28 @@ int machine_kexec_load(int type, int slot, xen_kexec_image_t *image) * in every odd index in page_list[]. */ - for (k = 0; k < KEXEC_XEN_NO_PAGES; k++) { - if ((k & 1) == 0) { /* even pages: machine address */ + for ( k = 0; k < KEXEC_XEN_NO_PAGES; k++ ) + { + if ( (k & 1) == 0 ) + { + /* Even pages: machine address. */ prev_ma = image->page_list[k]; } - else { /* odd pages: va for previous ma */ + else + { + /* Odd pages: va for previous ma. */ set_fixmap(fix_base + (k >> 1), prev_ma); image->page_list[k] = fix_to_virt(fix_base + (k >> 1)); } } - return 0; + return 0; } void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) { } - + static void __machine_shutdown(void *data) { xen_kexec_image_t *image = (xen_kexec_image_t *)data; @@ -63,7 +68,7 @@ static void __machine_shutdown(void *data) machine_kexec(image); } - + void machine_shutdown(xen_kexec_image_t *image) { int reboot_cpu_id; @@ -71,10 +76,11 @@ void machine_shutdown(xen_kexec_image_t *image) reboot_cpu_id = 0; - if (!cpu_isset(reboot_cpu_id, cpu_online_map)) + if ( !cpu_isset(reboot_cpu_id, cpu_online_map) ) reboot_cpu_id = smp_processor_id(); - - if (reboot_cpu_id != smp_processor_id()) { + + if ( reboot_cpu_id != smp_processor_id() ) + { cpus_clear(reboot_cpu); cpu_set(reboot_cpu_id, reboot_cpu); on_selected_cpus(reboot_cpu, __machine_shutdown, image, 1, 0); @@ -82,7 +88,9 @@ void machine_shutdown(xen_kexec_image_t *image) ; /* nothing */ } else + { __machine_shutdown(image); + } BUG(); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 181ca84f5f..43d1f63b71 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -274,11 +274,11 @@ static void srat_detect_node(int cpu) printk(KERN_INFO "CPU %d APIC %d -> Node %d\n", cpu, apicid, node); } -void __init move_memory(unsigned long dst, +void __init move_memory(unsigned long dst, unsigned long src_start, unsigned long src_end) { #if defined(CONFIG_X86_32) - memmove((void *)dst, /* use low mapping */ + memmove((void *)dst, /* use low mapping */ (void *)src_start, /* use low mapping */ src_end - src_start); #elif defined(CONFIG_X86_64) @@ -481,22 +481,23 @@ void __init __start_xen(multiboot_info_t *mbi) } machine_kexec_reserved(&crash_area); - if (crash_area.size > 0) { + if ( crash_area.size > 0 ) + { unsigned long kdump_start, kdump_size, k; - /* mark images pages as free for now */ + /* Mark images pages as free for now. */ init_boot_pages(initial_images_start, initial_images_end); kdump_start = crash_area.start; kdump_size = crash_area.size; - printk("Kdump: %luMB (%lukB) at 0x%lx\n", + printk("Kdump: %luMB (%lukB) at 0x%lx\n", kdump_size >> 20, kdump_size >> 10, kdump_start); - if ((kdump_start & ~PAGE_MASK) || (kdump_size & ~PAGE_MASK)) + if ( (kdump_start & ~PAGE_MASK) || (kdump_size & ~PAGE_MASK) ) panic("Kdump parameters not page aligned\n"); kdump_start >>= PAGE_SHIFT; @@ -506,7 +507,7 @@ void __init __start_xen(multiboot_info_t *mbi) k = alloc_boot_pages_at(kdump_size, kdump_start); - if (k != kdump_start) + if ( k != kdump_start ) panic("Unable to reserve Kdump memory\n"); /* allocate pages for relocated initial images */ @@ -516,7 +517,7 @@ void __init __start_xen(multiboot_info_t *mbi) k = alloc_boot_pages(k, 1); - if (!k) + if ( !k ) panic("Unable to allocate initial images memory\n"); move_memory(k << PAGE_SHIFT, initial_images_start, initial_images_end); @@ -524,12 +525,12 @@ void __init __start_xen(multiboot_info_t *mbi) initial_images_end -= initial_images_start; initial_images_start = k << PAGE_SHIFT; initial_images_end += initial_images_start; - } + } memguard_init(); percpu_guard_areas(); - printk("System RAM: %luMB (%lukB)\n", + printk("System RAM: %luMB (%lukB)\n", nr_pages >> (20 - PAGE_SHIFT), nr_pages << (PAGE_SHIFT - 10)); total_pages = nr_pages; diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 04fe8ef67f..20b338f834 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -1,6 +1,6 @@ /****************************************************************************** * kexec.c - Achitecture independent kexec code for Xen - * + * * Xen port written by: * - Simon 'Horms' Horman * - Magnus Damm @@ -42,7 +42,7 @@ spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED; static void one_cpu_only(void) { /* Only allow the first cpu to continue - force other cpus to spin */ - if (test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) + if ( test_and_set_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) ) { while (1); } @@ -55,7 +55,7 @@ void machine_crash_save_cpu(void) int cpu = smp_processor_id(); crash_note_t *cntp; - if (!cpu_test_and_set(cpu, crash_saved_cpus)) + if ( !cpu_test_and_set(cpu, crash_saved_cpus) ) { cntp = &per_cpu(crash_notes, cpu); elf_core_save_regs(&cntp->core.desc.desc.pr_reg, @@ -65,7 +65,7 @@ void machine_crash_save_cpu(void) setup_crash_note(cntp, core, CORE_STR, CORE_STR_LEN, NT_PRSTATUS); /* setup crash note "Xen", XEN_ELFNOTE_CRASH_REGS */ - setup_crash_note(cntp, xen_regs, XEN_STR, XEN_STR_LEN, + setup_crash_note(cntp, xen_regs, XEN_STR, XEN_STR_LEN, XEN_ELFNOTE_CRASH_REGS); } } @@ -83,7 +83,7 @@ crash_xen_info_t *machine_crash_save_info(void) cntp = &per_cpu(crash_notes, cpu); /* setup crash note "Xen", XEN_ELFNOTE_CRASH_INFO */ - setup_crash_note(cntp, xen_info, XEN_STR, XEN_STR_LEN, + setup_crash_note(cntp, xen_info, XEN_STR, XEN_STR_LEN, XEN_ELFNOTE_CRASH_INFO); info = &cntp->xen_info.desc.desc; @@ -106,7 +106,7 @@ void machine_crash_kexec(void) xen_kexec_image_t *image; one_cpu_only(); - + machine_crash_save_cpu(); crashing_cpu = smp_processor_id(); @@ -114,7 +114,7 @@ void machine_crash_kexec(void) pos = (test_bit(KEXEC_FLAG_CRASH_POS, &kexec_flags) != 0); - if (test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags)) + if ( test_bit(KEXEC_IMAGE_CRASH_BASE + pos, &kexec_flags) ) { image = &kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]; machine_kexec(image); /* Does not return */ @@ -140,7 +140,7 @@ void machine_kexec_reserved(xen_kexec_reserve_t *reservation) { unsigned long val[2]; char *str = opt_crashkernel; - int k = 0; + int k = 0; memset(reservation, 0, sizeof(*reservation)); @@ -170,7 +170,7 @@ void machine_kexec_reserved(xen_kexec_reserve_t *reservation) static int kexec_get_reserve(xen_kexec_range_t *range) { xen_kexec_reserve_t reservation; - + machine_kexec_reserved(&reservation); range->start = reservation.start; @@ -182,7 +182,7 @@ extern unsigned long _text, _end; static int kexec_get_xen(xen_kexec_range_t *range, int get_ma) { - if (get_ma) + if ( get_ma ) range->start = virt_to_maddr(&_text); else range->start = (unsigned long) &_text; @@ -193,7 +193,7 @@ static int kexec_get_xen(xen_kexec_range_t *range, int get_ma) static int kexec_get_cpu(xen_kexec_range_t *range) { - if (range->nr < 0 || range->nr >= num_present_cpus()) + if ( range->nr < 0 || range->nr >= num_present_cpus() ) return -EINVAL; range->start = __pa((unsigned long)&per_cpu(crash_notes, range->nr)); @@ -205,11 +205,11 @@ static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg) { xen_kexec_range_t range; int ret = -EINVAL; - - if (unlikely(copy_from_guest(&range, uarg, 1))) + + if ( unlikely(copy_from_guest(&range, uarg, 1)) ) return -EFAULT; - switch (range.range) + switch ( range.range ) { case KEXEC_RANGE_MA_CRASH: ret = kexec_get_reserve(&range); @@ -225,15 +225,15 @@ static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg) break; } - if (ret == 0 && unlikely(copy_to_guest(uarg, &range, 1))) + if ( ret == 0 && unlikely(copy_to_guest(uarg, &range, 1)) ) return -EFAULT; - + return ret; } static int kexec_load_get_bits(int type, int *base, int *bit) { - switch (type) + switch ( type ) { case KEXEC_TYPE_DEFAULT: *base = KEXEC_IMAGE_DEFAULT_BASE; @@ -256,24 +256,24 @@ static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) int base, bit, pos; int ret = 0; - if (unlikely(copy_from_guest(&load, uarg, 1))) + if ( unlikely(copy_from_guest(&load, uarg, 1)) ) return -EFAULT; - if (kexec_load_get_bits(load.type, &base, &bit)) + if ( kexec_load_get_bits(load.type, &base, &bit) ) return -EINVAL; pos = (test_bit(bit, &kexec_flags) != 0); /* Load the user data into an unused image */ - if (op == KEXEC_CMD_kexec_load) + if ( op == KEXEC_CMD_kexec_load ) { image = &kexec_image[base + !pos]; BUG_ON(test_bit((base + !pos), &kexec_flags)); /* must be free */ memcpy(image, &load.image, sizeof(*image)); - - if (!(ret = machine_kexec_load(load.type, base + !pos, image))) + + if ( !(ret = machine_kexec_load(load.type, base + !pos, image)) ) { /* Set image present bit */ set_bit((base + !pos), &kexec_flags); @@ -284,9 +284,9 @@ static int kexec_load_unload(unsigned long op, XEN_GUEST_HANDLE(void) uarg) } /* Unload the old image if present and load successful */ - if (ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags)) + if ( ret == 0 && !test_bit(KEXEC_FLAG_IN_PROGRESS, &kexec_flags) ) { - if (test_and_clear_bit((base + pos), &kexec_flags)) + if ( test_and_clear_bit((base + pos), &kexec_flags) ) { image = &kexec_image[base + pos]; machine_kexec_unload(load.type, base + pos, image); @@ -302,16 +302,16 @@ static int kexec_exec(XEN_GUEST_HANDLE(void) uarg) xen_kexec_image_t *image; int base, bit, pos; - if (unlikely(copy_from_guest(&exec, uarg, 1))) + if ( unlikely(copy_from_guest(&exec, uarg, 1)) ) return -EFAULT; - if (kexec_load_get_bits(exec.type, &base, &bit)) + if ( kexec_load_get_bits(exec.type, &base, &bit) ) return -EINVAL; pos = (test_bit(bit, &kexec_flags) != 0); /* Only allow kexec/kdump into loaded images */ - if (!test_bit(base + pos, &kexec_flags)) + if ( !test_bit(base + pos, &kexec_flags) ) return -ENOENT; switch (exec.type) @@ -334,10 +334,10 @@ long do_kexec_op(unsigned long op, XEN_GUEST_HANDLE(void) uarg) unsigned long flags; int ret = -EINVAL; - if ( !IS_PRIV(current->domain) ) + if ( !IS_PRIV(current->domain) ) return -EPERM; - switch (op) + switch ( op ) { case KEXEC_CMD_kexec_get_range: ret = kexec_get_range(uarg); From 252d27963b7d4ace036167beab940080696ef4f5 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 12:39:35 +0000 Subject: [PATCH 075/282] [XEN] kexec: use parse_size_and_unit() when parsing crashkernel command line parameter. Signed-off-by: Ian Campbell --- xen/common/kexec.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 20b338f834..ae3f0e6c70 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -138,32 +138,21 @@ __initcall(register_crashdump_trigger); void machine_kexec_reserved(xen_kexec_reserve_t *reservation) { - unsigned long val[2]; + unsigned long start, size; char *str = opt_crashkernel; - int k = 0; memset(reservation, 0, sizeof(*reservation)); - while (k < ARRAY_SIZE(val)) { - if (*str == '\0') { - break; - } - val[k] = simple_strtoul(str, &str, 0); - switch (toupper(*str)) { - case 'G': val[k] <<= 10; - case 'M': val[k] <<= 10; - case 'K': val[k] <<= 10; - str++; - } - if (*str == '@') { - str++; - } - k++; - } + size = parse_size_and_unit(str, &str); + if ( *str == '@' ) + start = parse_size_and_unit(str+1, NULL); + else + start = 0; - if (k == ARRAY_SIZE(val)) { - reservation->size = val[0]; - reservation->start = val[1]; + if ( start && size ) + { + reservation->start = start; + reservation->size = size; } } From dee3a9f6fa858406b4bd62d76ca617e4142e50d0 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 14:04:36 +0000 Subject: [PATCH 076/282] [XEN] Fix SIB byte decode when extended by REX.X and REX.B. Signed-off-by: Keir Fraser --- xen/arch/x86/x86_emulate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 22f63222f7..18921846ee 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -611,8 +611,8 @@ x86_emulate_memop( if ( modrm_rm == 4 ) { sib = insn_fetch(uint8_t); - sib_index = ((sib >> 3) & 7) | ((modrm << 2) & 8); - sib_base = (sib & 7) | ((modrm << 3) & 8); + sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8); + sib_base = (sib & 7) | ((rex_prefix << 3) & 8); if ( sib_index != 4 ) ea_off = *(long *)decode_register(sib_index, &_regs, 0); ea_off <<= (sib >> 6) & 3; From c4c2ab2a5f5efd532bc346705fdc46b78ffe2831 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 14:05:27 +0000 Subject: [PATCH 077/282] Update -xen0 defconfig for nhew kexec option Signed-off-by: Ian Campbell --- buildconfigs/linux-defconfig_xen0_x86_32 | 1 + buildconfigs/linux-defconfig_xen0_x86_64 | 1 + 2 files changed, 2 insertions(+) diff --git a/buildconfigs/linux-defconfig_xen0_x86_32 b/buildconfigs/linux-defconfig_xen0_x86_32 index 8cd6a5e503..78b2d95cf8 100644 --- a/buildconfigs/linux-defconfig_xen0_x86_32 +++ b/buildconfigs/linux-defconfig_xen0_x86_32 @@ -179,6 +179,7 @@ CONFIG_HZ_100=y # CONFIG_HZ_250 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 +CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set CONFIG_PHYSICAL_START=0x100000 diff --git a/buildconfigs/linux-defconfig_xen0_x86_64 b/buildconfigs/linux-defconfig_xen0_x86_64 index 05c6fed107..603e0a82d9 100644 --- a/buildconfigs/linux-defconfig_xen0_x86_64 +++ b/buildconfigs/linux-defconfig_xen0_x86_64 @@ -126,6 +126,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y # CONFIG_SPARSEMEM_STATIC is not set CONFIG_SPLIT_PTLOCK_CPUS=4096 CONFIG_SWIOTLB=y +CONFIG_KEXEC=y # CONFIG_CRASH_DUMP is not set CONFIG_PHYSICAL_START=0x100000 CONFIG_SECCOMP=y From 7dc9afed06334b83acd94717bd033d9dd94706a3 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:44:58 +0000 Subject: [PATCH 078/282] [XEND] Remove SXP from most parts of Xend. Attempt to get rid of most SXP dependency in Xend except in configuration parsing and certain places where it is required. XendConfig now stores configuration options similar to Xen API VM and devices attributes but exports an SXP version to certain things like xm and XendCheckpoint. All access to VM and device attributes should now use Python dictionaries rather than the SXP parser. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendAPI.py | 12 +- tools/python/xen/xend/XendCheckpoint.py | 4 +- tools/python/xen/xend/XendConfig.py | 1169 +++++++++-------- tools/python/xen/xend/XendDomain.py | 11 +- tools/python/xen/xend/XendDomainInfo.py | 314 +++-- tools/python/xen/xend/image.py | 134 +- tools/python/xen/xend/server/DevController.py | 7 +- tools/python/xen/xend/server/blkif.py | 21 +- tools/python/xen/xend/server/iopif.py | 4 +- tools/python/xen/xend/server/irqif.py | 2 +- tools/python/xen/xend/server/netif.py | 24 +- tools/python/xen/xend/server/pciif.py | 67 +- tools/python/xen/xend/server/pciquirk.py | 43 +- .../xen/xend/server/tests/test_controllers.py | 6 +- tools/python/xen/xend/server/tpmif.py | 12 +- tools/python/xen/xm/main.py | 4 +- 16 files changed, 968 insertions(+), 866 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 4f553b9bc3..081de0cf11 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -730,11 +730,11 @@ class XendAPI: def vm_get_memory_dynamic_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_memory_dynamic_max()) def vm_get_memory_dynamic_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_memory_dynamic_min()) def vm_get_VCPUs_policy(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -798,11 +798,11 @@ class XendAPI: def vm_get_builder(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_todo() + return xen_api_success(dom.get_builder()) def vm_get_boot_method(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) - return xen_api_success('') + return xen_api_success(dom.get_boot_method()) def vm_get_kernel_kernel(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) @@ -969,8 +969,8 @@ class XendAPI: 'resident_on': XendNode.instance().uuid, 'memory_static_min': xeninfo.get_memory_static_min(), 'memory_static_max': xeninfo.get_memory_static_max(), - 'memory_dynamic_min': xeninfo.get_memory_static_min(), - 'memory_dynamic_max': xeninfo.get_memory_static_max(), + 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(), + 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(), 'memory_actual': xeninfo.get_memory_static_min(), 'vcpus_policy': xeninfo.get_vcpus_policy(), 'vcpus_params': xeninfo.get_vcpus_params(), diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index b7c964d70a..707a9c5c3c 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -18,8 +18,8 @@ import xen.lowlevel.xc from xen.xend import balloon, sxp from xen.xend.XendError import XendError, VmError from xen.xend.XendLogging import log -from xen.xend.XendConstants import * from xen.xend.XendConfig import XendConfig +from xen.xend.XendConstants import * SIGNATURE = "LinuxGuestRecord" XC_SAVE = "xc_save" @@ -137,7 +137,7 @@ def restore(xd, fd, dominfo = None, paused = False): vmconfig = p.get_val() if dominfo: - dominfo.update(XendConfig(sxp = vmconfig), refresh = False) + dominfo.update(XendConfig(sxp_obj = vmconfig), refresh = False) dominfo.resume() else: dominfo = xd.restore_(vmconfig) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index da7898c72c..df124c06ca 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -31,31 +31,34 @@ from xen.xend.XendConstants import DOM_STATE_HALTED XendConfig API XendConfig will try to mirror as closely the Xen API VM Struct - providing a backwards compatibility mode for SXP dumping, loading. + with extra parameters for those options that are not supported. """ +def reverse_dict(adict): + """Return the reverse mapping of a dictionary.""" + return dict([(v, k) for k, v in adict.items()]) -LEGACY_CFG_TO_XENAPI_CFG = { +# Mapping from XendConfig configuration keys to the old +# legacy configuration keys that map directly. + +XENAPI_CFG_TO_LEGACY_CFG = { 'uuid': 'uuid', - 'vcpus': 'vcpus_number', - 'maxmem': 'memory_static_max', - 'memory': 'memory_static_min', - 'name': 'name_label', - 'on_poweroff': 'actions_after_shutdown', - 'on_reboot': 'actions_after_reboot', - 'on_crash': 'actions_after_crash', - 'bootloader': 'boot_method', - 'kernel_kernel': 'kernel_kernel', - 'kernel_initrd': 'kernel_initrd', - 'kernel_args': 'kernel_args', - } + 'vcpus_number': 'vcpus', + 'memory_static_min': 'memory', + 'memory_static_max': 'maxmem', + 'name_label': 'name', + 'actions_after_shutdown': 'on_poweroff', + 'actions_after_reboot': 'on_reboot', + 'actions_after_crash': 'on_crash', + 'platform_localtime': 'localtime', +} -XENAPI_CFG_CUSTOM_TRANSLATE = [ - 'vifs', - 'vbds', - ] +LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) +# Mapping from XendConfig configuration keys to the old +# legacy configuration keys that are found in the 'image' +# SXP object. XENAPI_HVM_CFG = { 'platform_std_vga': 'std-vga', 'platform_serial' : 'serial', @@ -64,7 +67,10 @@ XENAPI_HVM_CFG = { 'platform_keymap' : 'keymap', } -XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [ +# List of XendConfig configuration keys that have no equivalent +# in the old world. + +XENAPI_UNSUPPORTED_BY_LEGACY_CFG = [ 'name_description', 'user_version', 'is_a_template', @@ -85,11 +91,116 @@ XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [ 'platform_clock_offset', 'platform_enable_audio', 'platform_keymap', + 'boot_method', 'builder', 'grub_cmdline', 'pci_bus', 'otherconfig' - ] +] + +# List of legacy configuration keys that have no equivalent in the +# Xen API, but are still stored in XendConfig. + +LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [ + # roundtripped (dynamic, unmodified) + 'shadow_memory', + 'security', + 'vcpu_avail', + 'cpu_weight', + 'cpu_cap', + 'bootloader', + 'bootloader_args', + 'features', + # read/write + 'on_xend_start', + 'on_xend_stop', + # read-only + 'domid', + 'start_time', + 'cpu_time', + 'online_vcpus', + # write-once + 'cpu', + 'cpus', +] + +LEGACY_CFG_TYPES = { + 'uuid': str, + 'name': str, + 'vcpus': int, + 'vcpu_avail': int, + 'memory': int, + 'shadow_memory': int, + 'maxmem': int, + 'start_time': float, + 'cpu_cap': int, + 'cpu_weight': int, + 'cpu_time': float, + 'bootloader': str, + 'bootloader_args': str, + 'features': str, + 'localtime': int, + 'name': str, + 'on_poweroff': str, + 'on_reboot': str, + 'on_crash': str, + 'on_xend_stop': str, + 'on_xend_start': str, +} + +# Values that should be stored in xenstore's /vm/ that is used +# by Xend. Used in XendDomainInfo to restore running VM state from +# xenstore. +LEGACY_XENSTORE_VM_PARAMS = [ + 'uuid', + 'name', + 'vcpus', + 'vcpu_avail', + 'memory', + 'shadow_memory', + 'maxmem', + 'start_time', + 'name', + 'on_poweroff', + 'on_crash', + 'on_reboot', + 'on_xend_start', + 'on_xend_stop', +] + +LEGACY_IMAGE_CFG = [ + ('root', str), + ('ip', str), + ('nographic', int), + ('vnc', int), + ('sdl', int), + ('vncdisplay', int), + ('vncunused', int), +] + +LEGACY_IMAGE_HVM_CFG = [ + ('device_model', str), + ('display', str), + ('xauthority', str), + ('vncconsole', int), + ('pae', int), + ('apic', int), + ('acpi', int), + ('serial', str), +] + +LEGACY_IMAGE_HVM_DEVICES_CFG = [ + ('boot', str), + ('fda', str), + ('fdb', str), + ('soundhw', str), + ('isa', str), + ('vcpus', int), + ('acpi', int), + ('usb', str), + ('usbdevice', str), +] + # configuration params that need to be converted to ints @@ -102,74 +213,11 @@ XENAPI_INT_CFG = [ 'memory_static_max', 'memory_dynamic_min', 'memory_dynamic_max', + 'memory_actual', 'tpm_instance', 'tpm_backend', ] -## -## Xend Configuration Parameters -## - - -# All parameters of VMs that may be configured on-the-fly, or at start-up. -VM_CONFIG_ENTRIES = [ - ('name', str), - ('on_crash', str), - ('on_poweroff', str), - ('on_reboot', str), - ('on_xend_start', str), - ('on_xend_stop', str), -] - -# All entries written to the store. This is VM_CONFIG_ENTRIES, plus those -# entries written to the store that cannot be reconfigured on-the-fly. -VM_STORE_ENTRIES = [ - ('uuid', str), - ('vcpus', int), - ('vcpu_avail', int), - ('memory', int), - ('maxmem', int), - ('start_time', float), -] - -VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES - -# Configuration entries that we expect to round-trip -- be read from the -# config file or xc, written to save-files (i.e. through sxpr), and reused as -# config on restart or restore, all without munging. Some configuration -# entries are munged for backwards compatibility reasons, or because they -# don't come out of xc in the same form as they are specified in the config -# file, so those are handled separately. - -ROUNDTRIPPING_CONFIG_ENTRIES = [ - ('uuid', str), - ('vcpus', int), - ('vcpu_avail', int), - ('cpu_cap', int), - ('cpu_weight', int), - ('memory', int), - ('shadow_memory', int), - ('maxmem', int), - ('bootloader', str), - ('bootloader_args', str), - ('features', str), - ('localtime', int), -] -ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES - -## Static Configuration - -STATIC_CONFIG_ENTRIES = [ - ('cpu', int), - ('cpus', str), - ('image', list), - ('security', list), # TODO: what if null? -] - -DEPRECATED_ENTRIES = [ - ('restart', str), -] - ## ## Config Choices ## @@ -178,245 +226,152 @@ CONFIG_RESTART_MODES = ('restart', 'destroy', 'preserve', 'rename-restart') CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown', 'crashed', 'dying') -## -## Defaults -## - -def DEFAULT_VCPUS(info): - if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1 - else: return 1 - -DEFAULT_CONFIGURATION = ( - ('uuid', lambda info: uuid.createString()), - ('name', lambda info: 'Domain-' + info['uuid']), - - ('on_poweroff', lambda info: 'destroy'), - ('on_reboot', lambda info: 'restart'), - ('on_crash', lambda info: 'restart'), - ('features', lambda info: ''), - - - ('memory', lambda info: 0), - ('shadow_memory',lambda info: 0), - ('maxmem', lambda info: 0), - ('bootloader', lambda info: None), - ('bootloader_args', lambda info: None), - ('backend', lambda info: []), - ('device', lambda info: {}), - ('image', lambda info: None), - ('security', lambda info: []), - ('on_xend_start', lambda info: 'ignore'), - ('on_xend_stop', lambda info: 'ignore'), - - ('cpus', lambda info: []), - ('cpu_cap', lambda info: 0), - ('cpu_weight', lambda info: 256), - ('vcpus', lambda info: DEFAULT_VCPUS(info)), - ('online_vcpus', lambda info: info['vcpus']), - ('max_vcpu_id', lambda info: info['vcpus']-1), - ('vcpu_avail', lambda info: (1</image value and xm list.""" + image = [self['image'].get('type', 'linux')] + if self.has_key('kernel_kernel'): + image.append(['kernel', self['kernel_kernel']]) + if self.has_key('kernel_initrd') and self['kernel_initrd']: + image.append(['ramdisk', self['kernel_initrd']]) + if self.has_key('kernel_args') and self['kernel_args']: + image.append(['args', self['kernel_args']]) + + for arg, conv in LEGACY_IMAGE_CFG: + if self['image'].has_key(arg): + image.append([arg, self['image'][arg]]) + + if 'hvm' in self['image']: + for arg, conv in LEGACY_IMAGE_HVM_CFG: + if self['image']['hvm'].has_key(arg): + image.append([arg, self['image']['hvm'][arg]]) + + if 'hvm' in self['image'] and 'devices' in self['image']['hvm']: + for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: + if self['image']['hvm']['devices'].has_key(arg): + image.append([arg, + self['image']['hvm']['devices'][arg]]) + + return image + + def update_with_image_sxp(self, image_sxp): + # Convert Legacy "image" config to Xen API kernel_* + # configuration + self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','') + self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','') + kernel_args = sxp.child_value(image_sxp, 'args', '') + + # attempt to extract extra arguments from SXP config + arg_ip = sxp.child_value(image_sxp, 'ip') + if arg_ip and not re.search(r'ip=[0-9\.]', kernel_args): + kernel_args += ' ip=%s' % arg_ip + arg_root = sxp.child_value(image_sxp, 'root') + if arg_root and not re.search(r'root=', kernel_args): + kernel_args += ' root=%s' % arg_root + self['kernel_args'] = kernel_args + + # Store image SXP in python dictionary format + image = {} + image['type'] = sxp.name(image_sxp) + for arg, conv in LEGACY_IMAGE_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image[arg] = conv(val) + + image_hvm = {} + for arg, conv in LEGACY_IMAGE_HVM_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image_hvm[arg] = conv(val) + + image_hvm_devices = {} + for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: + val = sxp.child_value(image_sxp, arg, None) + if val != None: + image_hvm_devices[arg] = conv(val) + + if image_hvm or image_hvm_devices: + image['hvm'] = image_hvm + image['hvm']['devices'] = image_hvm_devices + + self['image'] = image + + for apikey, imgkey in XENAPI_HVM_CFG.items(): + val = sxp.child(image_sxp, imgkey, None) + if val != None: + self[apikey] = val + + # # debugging # diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 839acc8da6..b21f762d13 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -433,6 +433,11 @@ class XendDomain: """ log.debug("Adding Domain: %s" % info.getDomid()) self.domains[info.getDomid()] = info + + # update the managed domains with a new XendDomainInfo object + # if we are keeping track of it. + if info.get_uuid() in self.managed_domains: + self._managed_domain_register(info) def _remove_domain(self, info, domid = None): """Remove the domain from the list of running domains @@ -669,7 +674,7 @@ class XendDomain: self.domains_lock.acquire() try: try: - xeninfo = XendConfig(xenapi_vm = xenapi_vm) + xeninfo = XendConfig(xapi = xenapi_vm) dominfo = XendDomainInfo.createDormant(xeninfo) log.debug("Creating new managed domain: %s: %s" % (dominfo.getName(), dominfo.get_uuid())) @@ -873,8 +878,8 @@ class XendDomain: self.domains_lock.acquire() try: try: - xeninfo = XendConfig(sxp = config) - dominfo = XendDomainInfo.createDormant(xeninfo) + domconfig = XendConfig(sxp_obj = config) + dominfo = XendDomainInfo.createDormant(domconfig) log.debug("Creating new managed domain: %s" % dominfo.getName()) self._managed_domain_register(dominfo) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 26428a0304..fdf5dc4d71 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -38,10 +38,9 @@ from xen.util.blkif import blkdev_uname_to_file from xen.util import security from xen.xend import balloon, sxp, uuid, image, arch -from xen.xend import XendRoot, XendNode +from xen.xend import XendRoot, XendNode, XendConfig from xen.xend.XendBootloader import bootloader -from xen.xend.XendConfig import XendConfig from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices from xen.xend.xenstore.xstransact import xstransact, complete @@ -145,7 +144,7 @@ def create(config): """ log.debug("XendDomainInfo.create(%s)", config) - vm = XendDomainInfo(XendConfig(sxp = config)) + vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config)) try: vm.start() except: @@ -175,10 +174,9 @@ def recreate(info, priv): assert not info['dying'] - xeninfo = XendConfig(cfg = info) + xeninfo = XendConfig.XendConfig(dominfo = info) domid = xeninfo['domid'] - uuid1 = xeninfo['handle'] - xeninfo['uuid'] = uuid.toString(uuid1) + uuid1 = uuid.fromString(xeninfo['uuid']) needs_reinitialising = False dompath = GetDomainPath(domid) @@ -236,7 +234,7 @@ def recreate(info, priv): def restore(config): """Create a domain and a VM object to do a restore. - @param config: Domain configuration object + @param config: Domain SXP configuration @type config: list of lists. (see C{create}) @rtype: XendDomainInfo @@ -246,7 +244,8 @@ def restore(config): """ log.debug("XendDomainInfo.restore(%s)", config) - vm = XendDomainInfo(XendConfig(sxp = config), resume = True) + vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config), + resume = True) try: vm.resume() return vm @@ -254,24 +253,24 @@ def restore(config): vm.destroy() raise -def createDormant(xeninfo): +def createDormant(domconfig): """Create a dormant/inactive XenDomainInfo without creating VM. This is for creating instances of persistent domains that are not yet start. - @param xeninfo: Parsed configuration - @type xeninfo: dictionary + @param domconfig: Parsed configuration + @type domconfig: XendConfig object @rtype: XendDomainInfo @return: A up and running XendDomainInfo instance @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.createDormant(%s)", xeninfo) + log.debug("XendDomainInfo.createDormant(%s)", domconfig) # domid does not make sense for non-running domains. - xeninfo.pop('domid', None) - vm = XendDomainInfo(XendConfig(cfg = xeninfo)) + domconfig.pop('domid', None) + vm = XendDomainInfo(domconfig) return vm def domain_by_name(name): @@ -383,14 +382,6 @@ class XendDomainInfo: #if not self._infoIsSet('uuid'): # self.info['uuid'] = uuid.toString(uuid.create()) - #REMOVE: domid logic can be shortened - #if domid is not None: - # self.domid = domid - #elif info.has_key('dom'): - # self.domid = int(info['dom']) - #else: - # self.domid = None - self.vmpath = XS_VMROOT + self.info['uuid'] self.dompath = dompath @@ -403,6 +394,7 @@ class XendDomainInfo: self.vmWatch = None self.shutdownWatch = None self.shutdownStartTime = None + self._resume = resume self.state = DOM_STATE_HALTED self.state_updated = threading.Condition() @@ -416,8 +408,7 @@ class XendDomainInfo: if augment: self._augmentInfo(priv) - self._checkName(self.info['name']) - self.setResume(resume) + self._checkName(self.info['name_label']) # @@ -477,7 +468,7 @@ class XendDomainInfo: if self.domid == 0: raise XendError('Domain 0 cannot be shutdown') - if not reason in DOMAIN_SHUTDOWN_REASONS.values(): + if reason not in DOMAIN_SHUTDOWN_REASONS.values(): raise XendError('Invalid reason: %s' % reason) self._storeDom("control/shutdown", reason) @@ -512,12 +503,14 @@ class XendDomainInfo: """Create a new device. @param dev_config: device configuration - @type dev_config: dictionary (parsed config) + @type dev_config: SXP object (parsed config) """ log.debug("XendDomainInfo.device_create: %s" % dev_config) dev_type = sxp.name(dev_config) - devid = self._createDevice(dev_type, dev_config) - self.info.device_add(dev_type, cfg_sxp = dev_config) + dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) + dev_config_dict = self.info['devices'][dev_uuid][1] + log.debug("XendDomainInfo.device_create: %s" % dev_config_dict) + devid = self._createDevice(dev_type, dev_config_dict) self._waitForDevice(dev_type, devid) return self.getDeviceController(dev_type).sxpr(devid) @@ -525,12 +518,26 @@ class XendDomainInfo: """Configure an existing device. @param dev_config: device configuration - @type dev_config: dictionary (parsed config) + @type dev_config: SXP object (parsed config) @param devid: device id @type devid: int + @return: Returns True if successfully updated device + @rtype: boolean """ deviceClass = sxp.name(dev_config) - self._reconfigureDevice(deviceClass, devid, dev_config) + + # look up uuid of the device + dev_control = self.getDeviceController(deviceClass) + dev_sxpr = dev_control.sxpr(devid) + dev_uuid = sxp.child_value(sxpr, 'uuid') + if not dev_uuid: + return False + + self.info.device_update(dev_uuid, dev_config) + dev_config_dict = self.info['devices'].get(dev_uuid) + if dev_config_dict: + dev_control.reconfigureDevice(devid, dev_config_dict[1]) + return True def waitForDevices(self): """Wait for this domain's configured devices to connect. @@ -567,12 +574,12 @@ class XendDomainInfo: @param target: In MiB. """ log.debug("Setting memory target of domain %s (%d) to %d MiB.", - self.info['name'], self.domid, target) + self.info['name_label'], self.domid, target) if target <= 0: raise XendError('Invalid memory size') - self.info['memory'] = target + self.info['memory_static_min'] = target self.storeVm("memory", target) self._storeDom("memory/target", target << 10) @@ -581,8 +588,8 @@ class XendDomainInfo: # We include the domain name and ID, to help xm. sxpr = ['domain', ['domid', self.domid], - ['name', self.info['name']], - ['vcpu_count', self.info['online_vcpus']]] + ['name', self.info['name_label']], + ['vcpu_count', self.info['vcpus_number']]] for i in range(0, self.info['max_vcpu_id']+1): info = xc.vcpu_getinfo(self.domid, i) @@ -610,30 +617,40 @@ class XendDomainInfo: values taken from the store. This recovers those values known to xend but not to the hypervisor. """ - def useIfNeeded(name, val): - if not self._infoIsSet(name) and val is not None: - self.info[name] = val - + augment_entries = XendConfig.LEGACY_XENSTORE_VM_PARAMS[:] if priv: - entries = VM_STORE_ENTRIES[:] - entries.remove(('memory', int)) - entries.remove(('maxmem', int)) - else: - entries = VM_STORE_ENTRIES - entries.append(('image', str)) - entries.append(('security', str)) + augment_entries.remove('memory') + augment_entries.remove('maxmem') - map(lambda x, y: useIfNeeded(x[0], y), entries, - self._readVMDetails(entries)) + vm_config = self._readVMDetails([(k, XendConfig.LEGACY_CFG_TYPES[k]) + for k in augment_entries]) + + # make returned lists into a dictionary + vm_config = dict(zip(augment_entries, vm_config)) + + for arg in augment_entries: + xapicfg = arg + val = vm_config[arg] + if val != None: + if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: + xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] + self.info[xapiarg] = val + else: + self.info[arg] = val + # read image value + image_sxp = self._readVm('image') + if image_sxp: + self.info.update_with_image_sxp(sxp.from_string(image_sxp)) + + # read devices devices = [] - for devclass in XendDevices.valid_devices(): devconfig = self.getDeviceController(devclass).configurations() if devconfig: devices.extend(map(lambda conf: (devclass, conf), devconfig)) - if not self.info['device'] and devices is not None: + if not self.info['devices'] and devices is not None: for device in devices: self.info.device_add(device[0], cfg_sxp = device) @@ -678,16 +695,16 @@ class XendDomainInfo: def _recreateDomFunc(self, t): t.remove() t.mkdir() - t.set_permissions({ 'dom' : self.domid }) + t.set_permissions({'dom' : self.domid}) t.write('vm', self.vmpath) def _storeDomDetails(self): to_store = { 'domid': str(self.domid), 'vm': self.vmpath, - 'name': self.info['name'], + 'name': self.info['name_label'], 'console/limit': str(xroot.get_console_limit() * 1024), - 'memory/target': str(self.info['memory'] * 1024) + 'memory/target': str(self.info['memory_static_min'] * 1024) } def f(n, v): @@ -713,7 +730,7 @@ class XendDomainInfo: return 'offline' result = {} - for v in range(0, self.info['vcpus']): + for v in range(0, self.info['vcpus_number']): result["cpu/%d/availability" % v] = availability(v) return result @@ -735,19 +752,29 @@ class XendDomainInfo: log.trace("XendDomainInfo.storeChanged"); changed = False + + # Check whether values in the configuration have + # changed in Xenstore. - def f(x, y): - if y is not None and self.info[x[0]] != y: - self.info[x[0]] = y - changed = True + cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash'] + + vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k]) + for k in cfg_vm]) - map(f, VM_CONFIG_PARAMS, self._readVMDetails(VM_CONFIG_PARAMS)) + # convert two lists into a python dictionary + vm_details = dict(zip(cfg_vm, vm_details)) + + for arg, val in vm_details.items(): + if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG: + xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg] + if val != None and val != self.info[xapiarg]: + self.info[xapiarg] = val + changed= True - im = self._readVm('image') - current_im = self.info['image'] - if (im is not None and - (current_im is None or sxp.to_string(current_im) != im)): - self.info['image'] = sxp.from_string(im) + # Check whether image definition has been updated + image_sxp = self._readVm('image') + if image_sxp and image_sxp != self.info.image_sxpr(): + self.info.update_with_image_sxp(sxp.from_string(image_sxp)) changed = True if changed: @@ -791,11 +818,11 @@ class XendDomainInfo: def setName(self, name): self._checkName(name) - self.info['name'] = name + self.info['name_label'] = name self.storeVm("name", name) def getName(self): - return self.info['name'] + return self.info['name_label'] def getDomainPath(self): return self.dompath @@ -816,7 +843,7 @@ class XendDomainInfo: return self.info['features'] def getVCpuCount(self): - return self.info['vcpus'] + return self.info['vcpus_number'] def setVCpuCount(self, vcpus): self.info['vcpu_avail'] = (1 << vcpus) - 1 @@ -828,19 +855,19 @@ class XendDomainInfo: def getMemoryTarget(self): """Get this domain's target memory size, in KB.""" - return self.info['memory'] * 1024 + return self.info['memory_static_min'] * 1024 def getResume(self): - return "%s" % self.info['resume'] + return str(self._resume) def getCap(self): - return self.info['cpu_cap'] + return self.info.get('cpu_cap', 0) def getWeight(self): return self.info['cpu_weight'] def setResume(self, state): - self.info['resume'] = state + self._resume = state def getRestartCount(self): return self._readVm('xend/restart_count') @@ -891,7 +918,7 @@ class XendDomainInfo: return log.warn('Domain has crashed: name=%s id=%d.', - self.info['name'], self.domid) + self.info['name_label'], self.domid) if xroot.get_enable_dump(): self.dumpCore() @@ -910,7 +937,7 @@ class XendDomainInfo: reason = shutdown_reason(xeninfo['shutdown_reason']) log.info('Domain has shutdown: name=%s id=%d reason=%s.', - self.info['name'], self.domid, reason) + self.info['name_label'], self.domid, reason) self._clearRestart() @@ -945,7 +972,7 @@ class XendDomainInfo: if timeout < 0: log.info( "Domain shutdown timeout expired: name=%s id=%s", - self.info['name'], self.domid) + self.info['name_label'], self.domid) self.destroy() finally: self.refresh_shutdown_lock.release() @@ -965,11 +992,23 @@ class XendDomainInfo: def _maybeRestart(self, reason): # Dispatch to the correct method based upon the configured on_{reason} # behaviour. - {"destroy" : self.destroy, - "restart" : self._restart, - "preserve" : self._preserve, - "rename-restart" : self._renameRestart}[self.info['on_' + reason]]() + actions = {"destroy" : self.destroy, + "restart" : self._restart, + "preserve" : self._preserve, + "rename-restart" : self._renameRestart} + action_conf = { + 'poweroff': 'actions_after_shutdown', + 'reboot': 'actions_after_reboot', + 'crash': 'actions_after_crash', + } + + action_target = self.info.get(action_conf.get(reason)) + func = actions.get(action_target, None) + if func and callable(func): + func() + else: + self.destroy() # default to destroy def _renameRestart(self): self._restart(True) @@ -1008,7 +1047,7 @@ class XendDomainInfo: log.error( 'VM %s restarting too fast (%f seconds since the last ' 'restart). Refusing to restart to avoid loops.', - self.info['name'], timeout) + self.info['name_label'], timeout) self.destroy() return @@ -1055,11 +1094,11 @@ class XendDomainInfo: new_uuid = uuid.createString() new_name = 'Domain-%s' % new_uuid log.info("Renaming dead domain %s (%d, %s) to %s (%s).", - self.info['name'], self.domid, self.info['uuid'], + self.info['name_label'], self.domid, self.info['uuid'], new_name, new_uuid) self._unwatchVm() self._releaseDevices() - self.info['name'] = new_name + self.info['name_label'] = new_name self.info['uuid'] = new_uuid self.vmpath = XS_VMROOT + new_uuid self._storeVmDetails() @@ -1067,7 +1106,7 @@ class XendDomainInfo: def _preserve(self): - log.info("Preserving dead domain %s (%d).", self.info['name'], + log.info("Preserving dead domain %s (%d).", self.info['name_label'], self.domid) self._unwatchVm() self._storeDom('xend/shutdown_completed', 'True') @@ -1084,7 +1123,7 @@ class XendDomainInfo: if not corefile: this_time = time.strftime("%Y-%m%d-%H%M.%S", time.localtime()) corefile = "/var/xen/dump/%s-%s.%s.core" % (this_time, - self.info['name'], self.domid) + self.info['name_label'], self.domid) if os.path.isdir(corefile): raise XendError("Cannot dump core in a directory: %s" % @@ -1095,7 +1134,7 @@ class XendDomainInfo: corefile_incomp = corefile+'-incomplete' os.rename(corefile, corefile_incomp) log.exception("XendDomainInfo.dumpCore failed: id = %s name = %s", - self.domid, self.info['name']) + self.domid, self.info['name_label']) raise XendError("Failed to dump core: %s" % str(ex)) # @@ -1117,8 +1156,8 @@ class XendDomainInfo: @raise: VmError for invalid devices """ - for (devclass, config) in self.info.all_devices_sxpr(): - if devclass in XendDevices.valid_devices(): + for (devclass, config) in self.info.get('devices', {}).values(): + if devclass in XendDevices.valid_devices(): log.info("createDevice: %s : %s" % (devclass, config)) self._createDevice(devclass, config) @@ -1139,7 +1178,7 @@ class XendDomainInfo: # there's nothing more we can do. log.exception( "Device release failed: %s; %s; %s", - self.info['name'], devclass, dev) + self.info['name_label'], devclass, dev) if t.commit(): break @@ -1211,11 +1250,12 @@ class XendDomainInfo: log.debug('XendDomainInfo.constructDomain') - hvm = (self._infoIsSet('image') and - sxp.name(self.info['image']) == "hvm") + image_cfg = self.info.get('image', {}) + hvm = image_cfg.has_key('hvm') + if hvm: info = xc.xeninfo() - if not 'hvm' in info['xen_caps']: + if 'hvm' not in info['xen_caps']: raise VmError("HVM guest support is unavailable: is VT/AMD-V " "supported by your CPU and enabled in your " "BIOS?") @@ -1228,14 +1268,14 @@ class XendDomainInfo: if self.domid < 0: raise VmError('Creating domain failed: name=%s' % - self.info['name']) + self.info['name_label']) self.dompath = GetDomainPath(self.domid) self._recreateDom() # Set maximum number of vcpus in domain - xc.domain_max_vcpus(self.domid, int(self.info['vcpus'])) + xc.domain_max_vcpus(self.domid, int(self.info['vcpus_number'])) def _introduceDomain(self): @@ -1256,7 +1296,7 @@ class XendDomainInfo: # if we have a boot loader but no image, then we need to set things # up by running the boot loader non-interactively - if self._infoIsSet('bootloader') and not self._infoIsSet('image'): + if self.info.get('bootloader') and self.info.get('image'): self._configureBootloader() if not self._infoIsSet('image'): @@ -1264,8 +1304,9 @@ class XendDomainInfo: try: self.image = image.create(self, + self.info, self.info['image'], - self.info.all_devices_sxpr()) + self.info['devices']) localtime = self.info.get('localtime', 0) if localtime is not None and localtime == 1: @@ -1284,12 +1325,12 @@ class XendDomainInfo: # the various headrooms necessary, given the raw configured # values. maxmem, memory, and shadow are all in KiB. maxmem = self.image.getRequiredAvailableMemory( - self.info['maxmem'] * 1024) + self.info['memory_static_min'] * 1024) memory = self.image.getRequiredAvailableMemory( - self.info['memory'] * 1024) + self.info['memory_static_max'] * 1024) shadow = self.image.getRequiredShadowMemory( self.info['shadow_memory'] * 1024, - self.info['maxmem'] * 1024) + self.info['memory_static_max'] * 1024) # Round shadow up to a multiple of a MiB, as shadow_mem_control # takes MiB and we must not round down and end up under-providing. @@ -1317,7 +1358,7 @@ class XendDomainInfo: self._createDevices() - if self.info['bootloader'] not in [None, 'kernel_external']: + if self.info['bootloader']: self.image.cleanupBootloading() self.info['start_time'] = time.time() @@ -1325,7 +1366,7 @@ class XendDomainInfo: self._stateSet(DOM_STATE_RUNNING) except RuntimeError, exn: log.exception("XendDomainInfo.initDomain: exception occurred") - if self.info['bootloader'] not in [None, 'kernel_external'] \ + if self.info['bootloader'] not in (None, 'kernel_external') \ and self.image is not None: self.image.cleanupBootloading() raise VmError(str(exn)) @@ -1338,7 +1379,6 @@ class XendDomainInfo: self.refresh_shutdown_lock.acquire() try: self.unwatchShutdown() - self._releaseDevices() if self.image: @@ -1459,14 +1499,14 @@ class XendDomainInfo: def _configureBootloader(self): """Run the bootloader if we're configured to do so.""" - if not self.info['bootloader']: + if not self.info.get('bootloader'): return blcfg = None # FIXME: this assumes that we want to use the first disk device - for (n, c) in self.info.all_devices_sxpr(): - if not n or not c or not(n in ["vbd", "tap"]): + for devuuid, (devtype, devinfo) in self.info.all_devices_sxpr(): + if not devtype or not devinfo or devtype not in ('vbd', 'tap'): continue - disk = sxp.child_value(c, "uname") + disk = devinfo.get('uname') if disk is None: continue fn = blkdev_uname_to_file(disk) @@ -1478,7 +1518,8 @@ class XendDomainInfo: msg = "Had a bootloader specified, but can't find disk" log.error(msg) raise VmError(msg) - self.info['image'] = blcfg + + self.info.update_with_image_sxp(blcfg) # # VM Functions @@ -1516,7 +1557,8 @@ class XendDomainInfo: if arch.type == "x86": # 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than # the minimum that Xen would allocate if no value were given. - overhead_kb = self.info['vcpus'] * 1024 + self.info['maxmem'] * 4 + overhead_kb = self.info['vcpus_number'] * 1024 + \ + self.info['memory_static_max'] * 4 overhead_kb = ((overhead_kb + 1023) / 1024) * 1024 # The domain might already have some shadow memory overhead_kb -= xc.shadow_mem_control(self.domid) * 1024 @@ -1558,12 +1600,15 @@ class XendDomainInfo: def _storeVmDetails(self): to_store = {} - for k in VM_STORE_ENTRIES: - if self._infoIsSet(k[0]): - to_store[k[0]] = str(self.info[k[0]]) + for key in XendConfig.LEGACY_XENSTORE_VM_PARAMS: + info_key = XendConfig.LEGACY_CFG_TO_XENAPI_CFG.get(key, key) + if self._infoIsSet(info_key): + to_store[key] = str(self.info[info_key]) - if self._infoIsSet('image'): - to_store['image'] = sxp.to_string(self.info['image']) + if self.info.get('image'): + image_sxpr = self.info.image_sxpr() + if image_sxpr: + to_store['image'] = sxp.to_string(image_sxpr) if self._infoIsSet('security'): secinfo = self.info['security'] @@ -1656,6 +1701,7 @@ class XendDomainInfo: #create new security element self.info.update({'security': [['ssidref', str(info['ssidref'])]]}) + #ssidref field not used any longer if 'ssidref' in info: info.pop('ssidref') @@ -1663,8 +1709,7 @@ class XendDomainInfo: # make sure state is reset for info # TODO: we should eventually get rid of old_dom_states - self.info.update(info) - self.info.validate() + self.info.update_config(info) if refresh: self.refreshShutdown(info) @@ -1673,7 +1718,7 @@ class XendDomainInfo: str(self.domid), self.info) def sxpr(self, ignore_store = False): - result = self.info.get_sxp(domain = self, + result = self.info.to_sxp(domain = self, ignore_devices = ignore_store) if not ignore_store and self.dompath: @@ -1695,9 +1740,15 @@ class XendDomainInfo: return dom_uuid def get_memory_static_max(self): - return self.info['maxmem'] + return self.info['memory_static_max'] def get_memory_static_min(self): - return self.info['memory'] + return self.info['memory_static_min'] + def get_memory_dynamic_max(self): + return self.info['memory_dynamic_min'] + def get_memory_dynamic_min(self): + return self.info['memory_static_min'] + + def get_vcpus_policy(self): sched_id = xc.sched_id_get() if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF: @@ -1717,21 +1768,17 @@ class XendDomainInfo: def get_platform_keymap(self): return '' def get_platform_serial(self): - return '' # TODO + return self.info['platform_serial'] def get_platform_localtime(self): - return False # TODO + return self.info['platform_localtime'] def get_platform_clock_offset(self): - return False # TODO + return self.info['platform_clock_offset'] def get_platform_enable_audio(self): - return False # TODO + return self.info['platform_enable_audio'] def get_builder(self): - return 'Linux' # TODO + return self.info['builder'] def get_boot_method(self): - bootloader = self.info['bootloader'] - if not bootloader or bootloader not in XEN_API_BOOT_TYPE: - return 'kernel_external' - return bootloader - + return self.info['boot_method'] def get_kernel_image(self): return self.info['kernel_kernel'] def get_kernel_initrd(self): @@ -1748,25 +1795,26 @@ class XendDomainInfo: return {} # TODO def get_on_shutdown(self): - after_shutdown = self.info.get('on_poweroff') + after_shutdown = self.info.get('action_after_shutdown') if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_shutdown def get_on_reboot(self): - after_reboot = self.info.get('on_reboot') + after_reboot = self.info.get('action_after_reboot') if not after_reboot or after_reboot not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_reboot def get_on_suspend(self): - after_suspend = self.info.get('on_suspend') # TODO: not supported + # TODO: not supported + after_suspend = self.info.get('action_after_suspend') if not after_suspend or after_suspend not in XEN_API_ON_NORMAL_EXIT: return XEN_API_ON_NORMAL_EXIT[-1] return after_suspend def get_on_crash(self): - after_crash = self.info.get('on_crash') + after_crash = self.info.get('action_after_crash') if not after_crash or after_crash not in XEN_API_ON_CRASH_BEHAVIOUR: return XEN_API_ON_CRASH_BEHAVIOUR[0] return after_crash @@ -1780,7 +1828,7 @@ class XendDomainInfo: @rtype: dictionary """ - dev_type_config = self.info['device'].get(dev_uuid) + dev_type_config = self.info['devices'].get(dev_uuid) # shortcut if the domain isn't started because # the devcontrollers will have no better information @@ -1840,7 +1888,7 @@ class XendDomainInfo: config['IO_bandwidth_incoming_kbs'] = 0.0 config['IO_bandwidth_outgoing_kbs'] = 0.0 - if dev_class =='vbd': + if dev_class == 'vbd': config['VDI'] = '' # TODO config['device'] = config.get('dev', '') config['driver'] = 'paravirtualised' # TODO @@ -1984,8 +2032,8 @@ class XendDomainInfo: def __str__(self): return '' % \ - (str(self.domid), self.info['name'], - str(self.info['memory']), DOM_STATES[self.state]) + (str(self.domid), self.info['name_label'], + str(self.info['memory_static_min']), DOM_STATES[self.state]) __repr__ = __str__ diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 546e6eca38..98397d76ca 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -23,7 +23,6 @@ import math import signal import xen.lowlevel.xc -from xen.xend import sxp from xen.xend.XendError import VmError, XendError from xen.xend.XendLogging import log from xen.xend.server.netif import randomMAC @@ -31,19 +30,18 @@ from xen.xend.xenstore.xswatch import xswatch from xen.xend import arch from xen.xend import FlatDeviceTree - xc = xen.lowlevel.xc.xc() - MAX_GUEST_CMDLINE = 1024 -def create(vm, imageConfig, deviceConfig): +def create(vm, vmConfig, imageConfig, deviceConfig): """Create an image handler for a vm. @return ImageHandler instance """ - return findImageHandlerClass(imageConfig)(vm, imageConfig, deviceConfig) + return findImageHandlerClass(imageConfig)(vm, vmConfig, imageConfig, + deviceConfig) class ImageHandler: @@ -66,34 +64,20 @@ class ImageHandler: ostype = None - def __init__(self, vm, imageConfig, deviceConfig): + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): self.vm = vm self.kernel = None self.ramdisk = None self.cmdline = None - self.configure(imageConfig, deviceConfig) + self.configure(vmConfig, imageConfig, deviceConfig) - def configure(self, imageConfig, _): + def configure(self, vmConfig, imageConfig, _): """Config actions common to all unix-like domains.""" - - def get_cfg(name, default = None): - return sxp.child_value(imageConfig, name, default) - - self.kernel = get_cfg("kernel") - self.cmdline = "" - ip = get_cfg("ip") - if ip: - self.cmdline += " ip=" + ip - root = get_cfg("root") - if root: - self.cmdline += " root=" + root - args = get_cfg("args") - if args: - self.cmdline += " " + args - self.ramdisk = get_cfg("ramdisk", '') - + self.kernel = vmConfig['kernel_kernel'] + self.cmdline = vmConfig['kernel_args'] + self.ramdisk = vmConfig['kernel_initrd'] self.vm.storeVm(("image/ostype", self.ostype), ("image/kernel", self.kernel), ("image/cmdline", self.cmdline), @@ -214,8 +198,8 @@ class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" - def configure(self, imageConfig, deviceConfig): - LinuxImageHandler.configure(self, imageConfig, deviceConfig) + def configure(self, vmConfig, imageConfig, deviceConfig): + LinuxImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) self.imageConfig = imageConfig def buildDomain(self): @@ -248,25 +232,26 @@ class PPC_LinuxImageHandler(LinuxImageHandler): class HVMImageHandler(ImageHandler): - def __init__(self, vm, imageConfig, deviceConfig): - ImageHandler.__init__(self, vm, imageConfig, deviceConfig) + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): + ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig) self.shutdownWatch = None - def configure(self, imageConfig, deviceConfig): - ImageHandler.configure(self, imageConfig, deviceConfig) + def configure(self, vmConfig, imageConfig, deviceConfig): + ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) info = xc.xeninfo() - if not 'hvm' in info['xen_caps']: + if 'hvm' not in info['xen_caps']: raise VmError("HVM guest support is unavailable: is VT/AMD-V " "supported by your CPU and enabled in your BIOS?") self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig) - self.device_model = sxp.child_value(imageConfig, 'device_model') + self.device_model = imageConfig['hvm'].get('device_model') if not self.device_model: raise VmError("hvm: missing device model") - self.display = sxp.child_value(imageConfig, 'display') - self.xauthority = sxp.child_value(imageConfig, 'xauthority') - self.vncconsole = sxp.child_value(imageConfig, 'vncconsole') + + self.display = imageConfig['hvm'].get('display') + self.xauthority = imageConfig['hvm'].get('xauthority') + self.vncconsole = imageConfig['hvm'].get('vncconsole') self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)), ("image/device-model", self.device_model), @@ -276,9 +261,9 @@ class HVMImageHandler(ImageHandler): self.dmargs += self.configVNC(imageConfig) - self.pae = int(sxp.child_value(imageConfig, 'pae', 1)) - self.acpi = int(sxp.child_value(imageConfig, 'acpi', 1)) - self.apic = int(sxp.child_value(imageConfig, 'apic', 1)) + self.pae = imageConfig['hvm'].get('pae', 0) + self.acpi = imageConfig['hvm'].get('acpi', 0) + self.apic = imageConfig['hvm'].get('apic', 0) def buildDomain(self): store_evtchn = self.vm.getStorePort() @@ -312,8 +297,12 @@ class HVMImageHandler(ImageHandler): 'localtime', 'serial', 'stdvga', 'isa', 'vcpus', 'acpi', 'usb', 'usbdevice', 'keymap' ] ret = [] + hvmDeviceConfig = imageConfig['hvm']['devices'] + for a in dmargs: - v = sxp.child_value(imageConfig, a) + v = hvmDeviceConfig.get(a) + if a == 'vcpus': + v = hvmDeviceConfig.get('vcpus_number') # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' @@ -328,7 +317,7 @@ class HVMImageHandler(ImageHandler): ret.append("-%s" % a) ret.append("%s" % v) - if a in ['fda', 'fdb' ]: + if a in ['fda', 'fdb']: if v: if not os.path.isabs(v): raise VmError("Floppy file %s does not exist." % v) @@ -336,26 +325,27 @@ class HVMImageHandler(ImageHandler): # Handle disk/network related options mac = None - ret = ret + ["-domain-name", "%s" % self.vm.info['name']] + ret = ret + ["-domain-name", str(self.vm.info['name_label'])] nics = 0 - for (name, info) in deviceConfig: - if name == 'vbd': - uname = sxp.child_value(info, 'uname') + + for devuuid, (devtype, devinfo) in deviceConfig.items(): + if devtype == 'vbd': + uname = devinfo['uname'] if uname is not None and 'file:' in uname: (_, vbdparam) = string.split(uname, ':', 1) if not os.path.isfile(vbdparam): raise VmError('Disk image does not exist: %s' % vbdparam) - if name == 'vif': - type = sxp.child_value(info, 'type') - if type != 'ioemu': + if devtype == 'vif': + dtype = devinfo.get('type', 'ioemu') + if dtype != 'ioemu': continue nics += 1 - mac = sxp.child_value(info, 'mac') + mac = devinfo.get('mac') if mac == None: mac = randomMAC() - bridge = sxp.child_value(info, 'bridge', 'xenbr0') - model = sxp.child_value(info, 'model', 'rtl8139') + bridge = devinfo.get('bridge', 'xenbr0') + model = devinfo.get('model', 'rtl8139') ret.append("-net") ret.append("nic,vlan=%d,macaddr=%s,model=%s" % (nics, mac, model)) @@ -363,31 +353,32 @@ class HVMImageHandler(ImageHandler): ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge)) return ret - def configVNC(self, config): + def configVNC(self, imageConfig): # Handle graphics library related options - vnc = sxp.child_value(config, 'vnc') - sdl = sxp.child_value(config, 'sdl') + vnc = imageConfig.get('vnc') + sdl = imageConfig.get('sdl') ret = [] - nographic = sxp.child_value(config, 'nographic') + nographic = imageConfig.get('nographic') # get password from VM config (if password omitted, None) - vncpasswd_vmconfig = sxp.child_value(config, 'vncpasswd') + vncpasswd_vmconfig = imageConfig.get('vncpasswd') if nographic: ret.append('-nographic') return ret if vnc: - vncdisplay = int(sxp.child_value(config, 'vncdisplay', - self.vm.getDomid())) + vncdisplay = imageConfig.get('vncdisplay', + int(self.vm.getDomid())) + vncunused = imageConfig.get('vncunused') - vncunused = sxp.child_value(config, 'vncunused') if vncunused: ret += ['-vncunused'] else: ret += ['-vnc', '%d' % vncdisplay] - vnclisten = sxp.child_value(config, 'vnclisten') + vnclisten = imageConfig.get('vnclisten') + if not(vnclisten): vnclisten = (xen.xend.XendRoot.instance(). get_vnclisten_address()) @@ -423,21 +414,26 @@ class HVMImageHandler(ImageHandler): if self.vncconsole: args = args + ([ "-vncviewer" ]) log.info("spawning device models: %s %s", self.device_model, args) + # keep track of pid and spawned options to kill it later self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) log.info("device model pid: %d", self.pid) def destroy(self): - self.unregister_shutdown_watch(); + self.unregister_shutdown_watch() if not self.pid: return - os.kill(self.pid, signal.SIGKILL) - os.waitpid(self.pid, 0) + try: + os.kill(self.pid, signal.SIGKILL) + os.waitpid(self.pid, 0) + except OSError, e: + log.warning("Unable to kill device model (pid: %d)" % self.pid) + self.pid = 0 def register_shutdown_watch(self): """ add xen store watch on control/shutdown """ - self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", \ - self.hvm_shutdown) + self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", + self.hvm_shutdown) log.debug("hvm shutdown watch registered") def unregister_shutdown_watch(self): @@ -529,10 +525,10 @@ def findImageHandlerClass(image): @param image config @return ImageHandler subclass or None """ - type = sxp.name(image) - if type is None: + image_type = image['type'] + if image_type is None: raise VmError('missing image type') try: - return _handlers[arch.type][type] + return _handlers[arch.type][image_type] except KeyError: - raise VmError('unknown image type: ' + type) + raise VmError('unknown image type: ' + image_type) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index cbe3b18845..646e19d9de 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -17,6 +17,7 @@ #============================================================================ from threading import Event +import types from xen.xend import sxp from xen.xend.XendError import VmError @@ -86,7 +87,7 @@ class DevController: import xen.xend.XendDomain xd = xen.xend.XendDomain.instance() - backdom_name = sxp.child_value(config, 'backend') + backdom_name = config.get('backend') if backdom_name is None: backdom = xen.xend.XendDomain.DOM0_ID else: @@ -223,7 +224,7 @@ class DevController: configDict = self.getDeviceConfiguration(devid) sxpr = [self.deviceClass] for key, val in configDict.items(): - if type(val) == type(list()): + if isinstance(val, (types.ListType, types.TupleType)): for v in val: sxpr.append([key, v]) else: @@ -405,7 +406,7 @@ class DevController: import xen.xend.XendDomain xd = xen.xend.XendDomain.instance() - backdom_name = sxp.child_value(config, 'backend') + backdom_name = config.get('backend') if backdom_name: backdom = xd.domain_lookup_nr(backdom_name) else: diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 6bd49acfc9..16e2c5052d 100644 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -21,7 +21,6 @@ import string from xen.util import blkif from xen.util import security -from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -37,9 +36,9 @@ class BlkifController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - uname = sxp.child_value(config, 'uname', '') - dev = sxp.child_value(config, 'dev', '') - + uname = config.get('uname', '') + dev = config.get('dev', '') + if 'ioemu:' in dev: (_, dev) = string.split(dev, ':', 1) try: @@ -59,17 +58,17 @@ class BlkifController(DevController): except ValueError: (typ, params) = ("", "") - mode = sxp.child_value(config, 'mode', 'r') + mode = config.get('mode', 'r') if mode not in ('r', 'w', 'w!'): raise VmError('Invalid mode') - back = { 'dev' : dev, - 'type' : typ, - 'params' : params, - 'mode' : mode - } + back = {'dev' : dev, + 'type' : typ, + 'params' : params, + 'mode' : mode, + } - uuid = sxp.child_value(config, 'uuid') + uuid = config.get('uuid') if uuid: back['uuid'] = uuid diff --git a/tools/python/xen/xend/server/iopif.py b/tools/python/xen/xend/server/iopif.py index 96651a7c95..3b1a263736 100644 --- a/tools/python/xen/xend/server/iopif.py +++ b/tools/python/xen/xend/server/iopif.py @@ -22,7 +22,6 @@ import types import xen.lowlevel.xc -from xen.xend import sxp from xen.xend.XendError import VmError from xen.xend.server.DevController import DevController @@ -49,13 +48,12 @@ class IOPortsController(DevController): def __init__(self, vm): DevController.__init__(self, vm) - def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" def get_param(field): try: - val = sxp.child_value(config, field) + val = config.get(field) if not val: raise VmError('ioports: Missing %s config setting' % field) diff --git a/tools/python/xen/xend/server/irqif.py b/tools/python/xen/xend/server/irqif.py index 6e539dbab9..346ad7cf4d 100644 --- a/tools/python/xen/xend/server/irqif.py +++ b/tools/python/xen/xend/server/irqif.py @@ -45,7 +45,7 @@ class IRQController(DevController): def get_param(field): try: - val = sxp.child_value(config, field) + val = config.get(field) if not val: raise VmError('irq: Missing %s config setting' % field) diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index 4c7e359617..a20929a0d9 100644 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -24,7 +24,6 @@ import os import random import re -from xen.xend import sxp from xen.xend import XendRoot from xen.xend.server.DevController import DevController @@ -139,22 +138,15 @@ class NetifController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - def _get_config_ipaddr(config): - val = [] - for ipaddr in sxp.children(config, elt='ip'): - val.append(sxp.child0(ipaddr)) - return val - script = os.path.join(xroot.network_script_dir, - sxp.child_value(config, 'script', - xroot.get_vif_script())) - typ = sxp.child_value(config, 'type') - bridge = sxp.child_value(config, 'bridge') - mac = sxp.child_value(config, 'mac') - vifname = sxp.child_value(config, 'vifname') - rate = sxp.child_value(config, 'rate') - uuid = sxp.child_value(config, 'uuid') - ipaddr = _get_config_ipaddr(config) + config.get('script', xroot.get_vif_script())) + typ = config.get('type') + bridge = config.get('bridge') + mac = config.get('mac') + vifname = config.get('vifname') + rate = config.get('rate') + uuid = config.get('uuid') + ipaddr = config.get('ip') devid = self.allocateDeviceID() diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index eaab90529f..68af9d78cc 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -53,60 +53,29 @@ class PciController(DevController): def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" - #log.debug('pci config='+sxp.to_string(config)) - - def get_param(config, field, default=None): + def parse_hex(val): try: - val = sxp.child_value(config, field) - - if not val: - if default==None: - raise VmError('pci: Missing %s config setting' % field) - else: - return default - if isinstance(val, types.StringTypes): return int(val, 16) else: return val - except: - if default==None: - raise VmError('pci: Invalid config setting %s: %s' % - (field, val)) - else: - return default - - back = {} - - val = sxp.child_value(config, 'dev') - if isinstance(val, (types.ListType, types.TupleType)): - pcidevid = 0 - for dev_config in sxp.children(config, 'dev'): - domain = get_param(dev_config, 'domain', 0) - bus = get_param(dev_config,'bus') - slot = get_param(dev_config,'slot') - func = get_param(dev_config,'func') - - self.setupDevice(domain, bus, slot, func) - - back['dev-%i' % pcidevid]="%04x:%02x:%02x.%02x"% \ - (domain, bus, slot, func) - pcidevid+=1 + except ValueError: + return None - back['num_devs']=str(pcidevid) - - else: - # Xen 2.0 configuration compatibility - domain = get_param(config, 'domain', 0) - bus = get_param(config, 'bus') - slot = get_param(config, 'dev') - func = get_param(config, 'func') - + back = {} + pcidevid = 0 + for pci_config in config.get('devs', []): + domain = parse_hex(pci_config.get('domain', 0)) + bus = parse_hex(pci_config.get('bus', 0)) + slot = parse_hex(pci_config.get('slot', 0)) + func = parse_hex(pci_config.get('func', 0)) self.setupDevice(domain, bus, slot, func) + back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \ + (domain, bus, slot, func) + pcidevid += 1 - back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func) - back['num_devs']=str(1) - + back['num_devs']=str(pcidevid) + back['uuid'] = config.get('uuid','') return (0, back, {}) def getDeviceConfiguration(self, devid): @@ -129,7 +98,8 @@ class PciController(DevController): 'slot': '0x%(slot)s' % pci_dev_info, 'func': '0x%(func)s' % pci_dev_info}) - result['dev'] = pci_devs + result['devs'] = pci_devs + result['uuid'] = self.readBackend(devid, 'uuid') return result def configuration(self, devid): @@ -142,7 +112,8 @@ class PciController(DevController): sxpr = [self.deviceClass] # remove devs - devs = configDict.pop('dev', []) + devs = configDict.pop('devs', []) + for dev in devs: dev_sxpr = ['dev'] for dev_item in dev.items(): diff --git a/tools/python/xen/xend/server/pciquirk.py b/tools/python/xen/xend/server/pciquirk.py index ea53eee5b2..c0a4a68c83 100644 --- a/tools/python/xen/xend/server/pciquirk.py +++ b/tools/python/xen/xend/server/pciquirk.py @@ -15,25 +15,24 @@ class PCIQuirk: self.device = device self.subvendor = subvendor self.subdevice = subdevice - self.domain = domain - self.bus = bus - self.slot = slot - self.func = func + self.domain = domain + self.bus = bus + self.slot = slot + self.func = func self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, subdevice) - self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) + self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func) + self.quirks = self.__getQuirksByID() - self.quirks = self.__getQuirksByID( ) - - self.__sendQuirks( ) - self.__sendPermDevs( ) + self.__sendQuirks() + self.__sendPermDevs() def __matchPCIdev( self, list ): ret = False if list == None: return False for id in list: - if id.startswith( self.devid[:9] ): # id's vendor and device ID match + if id.startswith(self.devid[:9]): # id's vendor and device ID match skey = id.split(':') size = len(skey) if (size == 2): # subvendor/subdevice not suplied @@ -41,13 +40,13 @@ class PCIQuirk: break elif (size == 4): # check subvendor/subdevice # check subvendor - subven = '%04x' % self.subvendor + subven = '%04x' % self.subvendor if ((skey[2] != 'FFFF') and (skey[2] != 'ffff') and (skey[2] != subven)): continue # check subdevice - subdev = '%04x' % self.subdevice + subdev = '%04x' % self.subdevice if ((skey[3] != 'FFFF') and (skey[3] != 'ffff') and (skey[3] != subdev)): @@ -101,8 +100,8 @@ class PCIQuirk: self.slot, self.func, quirk) ) f.close() except Exception, e: - raise VmError("pci: failed to open/write/close quirks sysfs " + \ - "node - " + str(e)) + raise VmError("pci: failed to open/write/close quirks " + + "sysfs node - " + str(e)) def __devIsUnconstrained( self ): if os.path.exists(PERMISSIVE_CONFIG_FILE): @@ -126,20 +125,22 @@ class PCIQuirk: devices = child_at(child(pci_perm_dev_config, 'unconstrained_dev_ids'),0) if self.__matchPCIdev( devices ): - log.debug("Permissive mode enabled for PCI device [%s]" % self.devid) + log.debug("Permissive mode enabled for PCI device [%s]" % + self.devid) return True - log.debug("Permissive mode NOT enabled for PCI device [%s]" % self.devid) + log.debug("Permissive mode NOT enabled for PCI device [%s]" % + self.devid) return False def __sendPermDevs(self): if self.__devIsUnconstrained( ): - log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % (self.domain, - self.bus, self.slot, self.func)) + log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % + (self.domain, self.bus, self.slot, self.func)) try: f = file(PERMISSIVE_SYSFS_NODE ,"w") f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus, - self.slot, self.func) ) + self.slot, self.func)) f.close() except Exception, e: - raise VmError("pci: failed to open/write/close permissive " + \ - "sysfs node: " + str(e)) + raise VmError("pci: failed to open/write/close permissive " + + "sysfs node: " + str(e)) diff --git a/tools/python/xen/xend/server/tests/test_controllers.py b/tools/python/xen/xend/server/tests/test_controllers.py index 16b7941e5a..aa57f6321c 100644 --- a/tools/python/xen/xend/server/tests/test_controllers.py +++ b/tools/python/xen/xend/server/tests/test_controllers.py @@ -21,13 +21,13 @@ class test_controllers(unittest.TestCase): def testNetif(self): controller = self.controllerInstance(netif.NetifController) - self.assertNetif(controller.getDeviceDetails(['vif']), None) + self.assertNetif(controller.getDeviceDetails({}), None) self.assertNetif( - controller.getDeviceDetails( - ['vif', ['mac', 'aa:bb:cc:dd:ee:ff']]), + controller.getDeviceDetails({'mac': 'aa:bb:cc:dd:ee:ff'}), 'aa:bb:cc:dd:ee:ff') + def assertNetif(self, results, expectedMac): (devid, backdets, frontdets) = results diff --git a/tools/python/xen/xend/server/tpmif.py b/tools/python/xen/xend/server/tpmif.py index 494a197b8e..c2a5f1f64b 100644 --- a/tools/python/xen/xend/server/tpmif.py +++ b/tools/python/xen/xend/server/tpmif.py @@ -18,10 +18,8 @@ # Copyright (C) 2005 XenSource Ltd #============================================================================ -"""Support for virtual TPM interfaces. -""" +"""Support for virtual TPM interfaces.""" -from xen.xend import sxp from xen.xend import XendRoot from xen.xend.XendLogging import log from xen.xend.XendError import XendError @@ -49,12 +47,12 @@ class TPMifController(DevController): """@see DevController.getDeviceDetails""" devid = self.allocateDeviceID() - inst = int(sxp.child_value(config, 'pref_instance', '-1')) + inst = int(config.get('pref_instance', -1)) if inst == -1: - inst = int(sxp.child_value(config, 'instance' , '0')) + inst = int(config.get('instance', 0)) - typ = sxp.child_value(config, 'type') - uuid = sxp.child_value(config, 'uuid') + typ = config.get('type') + uuid = config.get('uuid') log.info("The domain has a TPM with pref. instance %d and devid %d.", inst, devid) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 93d2fe1029..9982dc3388 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -581,8 +581,8 @@ def parse_doms_info(info): return { 'domid' : get_info('domid', str, ''), 'name' : get_info('name', str, '??'), - 'mem' : get_info('memory_dynamic_max', int, 0), - 'vcpus' : get_info('online_vcpus', int, 0), + 'mem' : get_info('memory_dynamic_min', int, 0), + 'vcpus' : get_info('vcpus', int, 0), 'state' : get_info('state', str, ''), 'cpu_time' : get_info('cpu_time', float, 0), 'up_time' : get_info('up_time', float, -1), From 71710a8321ad082aa3861fd5ca9e8e6337cda8cc Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:46:45 +0000 Subject: [PATCH 079/282] [XEND] Fix hidden vcpu state when calling xm-list Stores the vcpus number in xenstore so it is preserved on xend restart. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendDomainInfo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index fdf5dc4d71..9581a9621e 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -847,7 +847,9 @@ class XendDomainInfo: def setVCpuCount(self, vcpus): self.info['vcpu_avail'] = (1 << vcpus) - 1 + self.info['vcpus_number'] = vcpus self.storeVm('vcpu_avail', self.info['vcpu_avail']) + self.storeVm('vcpus', self.info['vcpus_number']) self._writeDom(self._vcpuDomDetails()) def getLabel(self): From 75753a5ac92d545b9f606af107cd5005dab2caea Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:48:42 +0000 Subject: [PATCH 080/282] [XEND] Rename Xen API methods to match case of the API documentation Get rid of the case skewing in XendAPI. Remove _to_xml methods because it has been removed from the latest API docs. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendAPI.py | 332 +++++++++++++++---------------- 1 file changed, 162 insertions(+), 170 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 081de0cf11..7970eff00d 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -303,8 +303,8 @@ class XendAPI: # all get_by_uuid() methods. for cls in classes.keys(): - get_by_uuid = '%s_get_by_uuid' % cls.lower() - get_uuid = '%s_get_uuid' % cls.lower() + get_by_uuid = '%s_get_by_uuid' % cls + get_uuid = '%s_get_uuid' % cls setattr(XendAPI, get_by_uuid, lambda s, sess, obj_ref: xen_api_success(obj_ref)) setattr(XendAPI, get_uuid, @@ -327,7 +327,7 @@ class XendAPI: # wrap validators around readable class attributes for attr_name in ro_attrs + rw_attrs + self.Base_attr_ro: - getter_name = '%s_get_%s' % (cls.lower(), attr_name) + getter_name = '%s_get_%s' % (cls, attr_name) try: getter = getattr(XendAPI, getter_name) for validator in validators: @@ -340,7 +340,7 @@ class XendAPI: # wrap validators around writable class attrributes for attr_name in rw_attrs + self.Base_attr_rw: - setter_name = '%s_set_%s' % (cls.lower(), attr_name) + setter_name = '%s_set_%s' % (cls, attr_name) try: setter = getattr(XendAPI, setter_name) for validator in validators: @@ -353,7 +353,8 @@ class XendAPI: # wrap validators around methods for method_name in methods + self.Base_methods: - method_full_name = '%s_%s' % (cls.lower(), method_name) + method_full_name = '%s_%s' % (cls, method_name) + try: method = getattr(XendAPI, method_full_name) for validator in validators: @@ -366,7 +367,7 @@ class XendAPI: # wrap validators around class functions for func_name in funcs + self.Base_funcs: - func_full_name = '%s_%s' % (cls.lower(), func_name) + func_full_name = '%s_%s' % (cls, func_name) try: method = getattr(XendAPI, func_full_name) method = session_required(method) @@ -379,7 +380,7 @@ class XendAPI: Base_attr_ro = ['uuid'] Base_attr_rw = [] - Base_methods = ['destroy', 'to_XML', 'get_record'] + Base_methods = ['destroy', 'get_record'] Base_funcs = ['create', 'get_by_uuid', 'get_all'] # Xen API: Class Session @@ -411,8 +412,6 @@ class XendAPI: record = {'this_host': XendNode.instance().uuid, 'this_user': auth_manager().get_user(session)} return xen_api_success(record) - def session_to_XML(self, session): - return xen_api_todo() # attributes (ro) def session_get_this_host(self, session): @@ -536,8 +535,6 @@ class XendAPI: 'features': node.get_host_cpu_features(host_cpu_ref), 'utilisation': node.get_host_cpu_load(host_cpu_ref)} return xen_api_success(record) - def host_cpu_to_XML(self, session, host_cpu_ref): - return xen_api_todo() # class methods def host_cpu_get_all(self, session): @@ -656,304 +653,301 @@ class XendAPI: 'otherConfig'] # attributes (ro) - def vm_get_power_state(self, session, vm_ref): + def VM_get_power_state(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.state) - def vm_get_resident_on(self, session, vm_ref): + def VM_get_resident_on(self, session, vm_ref): return xen_api_success(XendNode.instance().uuid) - def vm_get_memory_actual(self, session, vm_ref): + def VM_get_memory_actual(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # unsupported by xc - def vm_get_memory_static_max(self, session, vm_ref): + def VM_get_memory_static_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_memory_static_max()) - def vm_get_memory_static_min(self, session, vm_ref): + def VM_get_memory_static_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_memory_static_min()) - def vm_get_VCPUs_number(self, session, vm_ref): + def VM_get_VCPUs_number(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.getVCpuCount()) - def vm_get_VCPUs_utilisation(self, session, vm_ref): + def VM_get_VCPUs_utilisation(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_vcpus_util()) - def vm_get_VCPUs_features_required(self, session, vm_ref): + def VM_get_VCPUs_features_required(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # unsupported by xc - def vm_get_VCPUs_can_use(self, session, vm_ref): + def VM_get_VCPUs_can_use(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # unsupported by xc - def vm_get_VIFs(self, session, vm_ref): + def VM_get_VIFs(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_vifs()) - def vm_get_VBDs(self, session, vm_ref): + def VM_get_VBDs(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_vbds()) - def vm_get_VTPMs(self, session, vm_ref): + def VM_get_VTPMs(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_vtpms()) - def vm_get_PCI_bus(self, session, vm_ref): + def VM_get_PCI_bus(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # unsupported by xc - def vm_get_tools_version(self, session, vm_ref): + def VM_get_tools_version(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # attributes (rw) - def vm_get_name_label(self, session, vm_ref): + def VM_get_name_label(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.getName()) - def vm_get_name_description(self, session, vm_ref): + def VM_get_name_description(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_user_version(self, session, vm_ref): + def VM_get_user_version(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_is_a_template(self, session, vm_ref): + def VM_get_is_a_template(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_memory_dynamic_max(self, session, vm_ref): + def VM_get_memory_dynamic_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_memory_dynamic_max()) - def vm_get_memory_dynamic_min(self, session, vm_ref): + def VM_get_memory_dynamic_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_memory_dynamic_min()) - def vm_get_VCPUs_policy(self, session, vm_ref): + def VM_get_VCPUs_policy(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # need to access scheduler - def vm_get_VCPUs_params(self, session, vm_ref): + def VM_get_VCPUs_params(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() # need access to scheduler - def vm_get_VCPUs_features_force_on(self, session, vm_ref): + def VM_get_VCPUs_features_force_on(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_VCPUs_features_force_off(self, session, vm_ref): + def VM_get_VCPUs_features_force_off(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_actions_after_shutdown(self, session, vm_ref): + def VM_get_actions_after_shutdown(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_on_shutdown()) - def vm_get_actions_after_reboot(self, session, vm_ref): + def VM_get_actions_after_reboot(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_on_reboot()) - def vm_get_actions_after_suspend(self, session, vm_ref): + def VM_get_actions_after_suspend(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_on_suspend()) - def vm_get_actions_after_crash(self, session, vm_ref): + def VM_get_actions_after_crash(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_on_crash()) - def vm_get_bios_boot(self, session, vm_ref): + def VM_get_bios_boot(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_bios_boot()) - def vm_get_platform_std_VGA(self, session, vm_ref): + def VM_get_platform_std_VGA(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_platform_serial(self, session, vm_ref): + def VM_get_platform_serial(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_platform_localtime(self, session, vm_ref): + def VM_get_platform_localtime(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_platform_clock_offset(self, session, vm_ref): + def VM_get_platform_clock_offset(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_platform_enable_audio(self, session, vm_ref): + def VM_get_platform_enable_audio(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_platform_keymap(self, session, vm_ref): + def VM_get_platform_keymap(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_get_builder(self, session, vm_ref): + def VM_get_builder(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_builder()) - def vm_get_boot_method(self, session, vm_ref): + def VM_get_boot_method(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success(dom.get_boot_method()) - def vm_get_kernel_kernel(self, session, vm_ref): + def VM_get_kernel_kernel(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success('') - def vm_get_kernel_initrd(self, session, vm_ref): + def VM_get_kernel_initrd(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success('') - def vm_get_kernel_args(self, session, vm_ref): + def VM_get_kernel_args(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success('') - def vm_get_grub_cmdline(self, session, vm_ref): + def VM_get_grub_cmdline(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success('') - def vm_get_otherConfig(self, session, vm_ref): + def VM_get_otherConfig(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def vm_set_name_label(self, session, vm_ref): + def VM_set_name_label(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_name_description(self, session, vm_ref): + def VM_set_name_description(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_user_version(self, session, vm_ref): + def VM_set_user_version(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_is_a_template(self, session, vm_ref): + def VM_set_is_a_template(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_memory_dynamic_max(self, session, vm_ref): + def VM_set_memory_dynamic_max(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_memory_dynamic_min(self, session, vm_ref): + def VM_set_memory_dynamic_min(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_VCPUs_policy(self, session, vm_ref): + def VM_set_VCPUs_policy(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_VCPUs_params(self, session, vm_ref): + def VM_set_VCPUs_params(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_VCPUs_features_force_on(self, session, vm_ref): + def VM_set_VCPUs_features_force_on(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_VCPUs_features_force_off(self, session, vm_ref): + def VM_set_VCPUs_features_force_off(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_actions_after_shutdown(self, session, vm_ref): + def VM_set_actions_after_shutdown(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_actions_after_reboot(self, session, vm_ref): + def VM_set_actions_after_reboot(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_actions_after_suspend(self, session, vm_ref): + def VM_set_actions_after_suspend(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_actions_after_crash(self, session, vm_ref): + def VM_set_actions_after_crash(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_bios_boot(self, session, vm_ref): + def VM_set_bios_boot(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_platform_std_VGA(self, session, vm_ref): + def VM_set_platform_std_VGA(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_platform_serial(self, session, vm_ref): + def VM_set_platform_serial(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_platform_localtime(self, session, vm_ref): + def VM_set_platform_localtime(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_platform_clock_offset(self, session, vm_ref): + def VM_set_platform_clock_offset(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_platform_enable_audio(self, session, vm_ref): + def VM_set_platform_enable_audio(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_builder(self, session, vm_ref): + def VM_set_builder(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_boot_method(self, session, vm_ref): + def VM_set_boot_method(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_kernel_kernel(self, session, vm_ref): + def VM_set_kernel_kernel(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_kernel_initrd(self, session, vm_ref): + def VM_set_kernel_initrd(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_kernel_args(self, session, vm_ref): + def VM_set_kernel_args(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_grub_cmdline(self, session, vm_ref): + def VM_set_grub_cmdline(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() - def vm_set_otherConfig(self, session, vm_ref): + def VM_set_otherConfig(self, session, vm_ref): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_success_void() # class methods - def vm_get_all(self, session): + def VM_get_all(self, session): refs = [d.get_uuid() for d in XendDomain.instance().list()] return xen_api_success(refs) - def vm_get_by_name_label(self, session, label): + def VM_get_by_name_label(self, session, label): xendom = XendDomain.instance() dom = xendom.domain_lookup_nr(label) if dom: return xen_api_success([dom.get_uuid()]) return xen_api_error(XEND_ERROR_VM_INVALID) - def vm_create(self, session, vm_struct): + def VM_create(self, session, vm_struct): xendom = XendDomain.instance() domuuid = xendom.create_domain(vm_struct) return xen_api_success(domuuid) # object methods - def vm_to_XML(self, session, vm_ref): - return xen_api_todo() - - def vm_get_record(self, session, vm_ref): + def VM_get_record(self, session, vm_ref): xendom = XendDomain.instance() xeninfo = xendom.get_vm_by_uuid(vm_ref) if not xeninfo: @@ -1006,41 +1000,39 @@ class XendAPI: } return xen_api_success(record) - def vm_clean_reboot(self, session, vm_ref): + def VM_clean_reboot(self, session, vm_ref): xendom = XendDomain.instance() xeninfo = xendom.get_vm_by_uuid(vm_ref) xeninfo.shutdown("reboot") return xen_api_success_void() - def vm_clean_shutdown(self, session, vm_ref): + def VM_clean_shutdown(self, session, vm_ref): xendom = XendDomain.instance() xeninfo = xendom.get_vm_by_uuid(vm_ref) xeninfo.shutdown("poweroff") return xen_api_success_void() - def vm_clone(self, session, vm_ref): + def VM_clone(self, session, vm_ref): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def vm_destroy(self, session, vm_ref): + def VM_destroy(self, session, vm_ref): return do_vm_func("domain_delete", vm_ref) - def vm_hard_reboot(self, session, vm_ref): + def VM_hard_reboot(self, session, vm_ref): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def vm_hard_shutdown(self, session, vm_ref): + def VM_hard_shutdown(self, session, vm_ref): return do_vm_func("domain_destroy", vm_ref) - def vm_pause(self, session, vm_ref): + def VM_pause(self, session, vm_ref): return do_vm_func("domain_pause", vm_ref) - def vm_resume(self, session, vm_ref, start_paused): + def VM_resume(self, session, vm_ref, start_paused): return do_vm_func("domain_resume", vm_ref, start_paused = start_paused) - def vm_start(self, session, vm_ref, start_paused): + def VM_start(self, session, vm_ref, start_paused): return do_vm_func("domain_start", vm_ref, start_paused = start_paused) - def vm_suspend(self, session, vm_ref): + def VM_suspend(self, session, vm_ref): return do_vm_func("domain_suspend", vm_ref) - def vm_unpause(self, session, vm_ref): + def VM_unpause(self, session, vm_ref): return do_vm_func("domain_unpause", vm_ref) - # Xen API: Class VDI - # ---------------------------------------------------------------- - # TODO: NOT IMPLEMENTED. - # Xen API: Class VBD # ---------------------------------------------------------------- + # Note: accepts a non-API standard 'image' attribute to emulate + # regular xm created VBDs VBD_attr_ro = ['image', 'IO_bandwidth_incoming_kbs', @@ -1053,8 +1045,10 @@ class XendAPI: VBD_attr_inst = VBD_attr_rw + ['image'] + VBD_methods = ['media_change'] + # object methods - def vbd_get_record(self, session, vbd_ref): + def VBD_get_record(self, session, vbd_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vbd', vbd_ref) if not vm: @@ -1063,9 +1057,12 @@ class XendAPI: if not cfg: return xen_api_error(XEND_ERROR_VBD_INVALID) return xen_api_success(cfg) - + + def VBD_media_change(self, session, vbd_ref, vdi_ref): + return xen_api_error(XEND_ERROR_UNSUPPORTED) + # class methods - def vbd_create(self, session, vbd_struct): + def VBD_create(self, session, vbd_struct): xendom = XendDomain.instance() if not xendom.is_valid_vm(vbd_struct['VM']): return xen_api_error(XEND_ERROR_DOMAIN_INVALID) @@ -1092,22 +1089,22 @@ class XendAPI: return xen_api_success(vbd_ref) # attributes (rw) - def vbd_get_VM(self, session, vbd_ref): + def VBD_get_VM(self, session, vbd_ref): xendom = XendDomain.instance() return xen_api_success(xendom.get_dev_property('vbd', vbd_ref, 'VM')) - def vbd_get_VDI(self, session, vbd_ref): + def VBD_get_VDI(self, session, vbd_ref): return xen_api_todo() - def vbd_get_device(self, session, vbd_ref): + def VBD_get_device(self, session, vbd_ref): xendom = XendDomain.instance() return xen_api_success(xendom.get_dev_property('vbd', vbd_ref, 'device')) - def vbd_get_mode(self, session, vbd_ref): + def VBD_get_mode(self, session, vbd_ref): xendom = XendDomain.instance() return xen_api_success(xendom.get_dev_property('vbd', vbd_ref, 'mode')) - def vbd_get_driver(self, session, vbd_ref): + def VBD_get_driver(self, session, vbd_ref): xendom = XendDomain.instance() return xen_api_success(xendom.get_dev_property('vbd', vbd_ref, 'driver')) @@ -1130,7 +1127,7 @@ class XendAPI: VIF_attr_inst = VIF_attr_rw # object methods - def vif_get_record(self, session, vif_ref): + def VIF_get_record(self, session, vif_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vif', vif_ref) if not vm: @@ -1147,7 +1144,7 @@ class XendAPI: return xen_api_success(cfg) # class methods - def vif_create(self, session, vif_struct): + def VIF_create(self, session, vif_struct): xendom = XendDomain.instance() if xendom.is_valid_vm(vif_struct['VM']): dom = xendom.get_vm_by_uuid(vif_struct['VM']) @@ -1180,99 +1177,96 @@ class XendAPI: VDI_methods = ['snapshot'] VDI_funcs = ['get_by_name_label'] - def vdi_get_VBDs(self, session, vdi_ref): + def VDI_get_VBDs(self, session, vdi_ref): return xen_api_todo() - def vdi_get_physical_utilisation(self, session, vdi_ref): + def VDI_get_physical_utilisation(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.get_physical_utilisation()) - def vdi_get_sector_size(self, session, vdi_ref): + def VDI_get_sector_size(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.sector_size) - def vdi_get_type(self, session, vdi_ref): + def VDI_get_type(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.type) - def vdi_get_parent(self, session, vdi_ref): + def VDI_get_parent(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.parent) - def vdi_get_children(self, session, vdi_ref): + def VDI_get_children(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.children) - def vdi_get_name_label(self, session, vdi_ref): + def VDI_get_name_label(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.name_label) - def vdi_get_name_description(self, session, vdi_ref): + def VDI_get_name_description(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.name_description) - def vdi_get_SR(self, session, vdi_ref): + def VDI_get_SR(self, session, vdi_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.uuid) - def vdi_get_virtual_size(self, session, vdi_ref): + def VDI_get_virtual_size(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.virtual_size) - def vdi_get_sharable(self, session, vdi_ref): + def VDI_get_sharable(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.sharable) - def vdi_get_read_only(self, session, vdi_ref): + def VDI_get_read_only(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) return xen_api_success(image.sharable) - def vdi_set_name_label(self, session, vdi_ref, value): + def VDI_set_name_label(self, session, vdi_ref, value): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) image.name_label = value return xen_api_success_void() - def vdi_set_name_description(self, session, vdi_ref, value): + def VDI_set_name_description(self, session, vdi_ref, value): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) image.name_description = value return xen_api_success_void() - def vdi_set_SR(self, session, vdi_ref, value): + def VDI_set_SR(self, session, vdi_ref, value): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def vdi_set_virtual_size(self, session, vdi_ref, value): + def VDI_set_virtual_size(self, session, vdi_ref, value): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def vdi_set_sharable(self, session, vdi_ref, value): + def VDI_set_sharable(self, session, vdi_ref, value): return xen_api_todo() - def vdi_set_read_only(self, session, vdi_ref, value): + def VDI_set_read_only(self, session, vdi_ref, value): return xen_api_todo() # Object Methods - def vdi_snapshot(self, session, vdi_ref): + def VDI_snapshot(self, session, vdi_ref): return xen_api_todo() - def vdi_destroy(self, session, vdi_ref): + def VDI_destroy(self, session, vdi_ref): sr = XendNode.instance().get_sr() sr.destroy_image(vdi_ref) return xen_api_success_void() - def vdi_to_XML(self, session, vdi_ref): - return xen_api_todo() - - def vdi_get_record(self, session, vdi_ref): + def VDI_get_record(self, session, vdi_ref): sr = XendNode.instance().get_sr() image = sr.xen_api_get_by_uuid(vdi_ref) if image: @@ -1295,7 +1289,7 @@ class XendAPI: return xen_api_error(XEND_ERROR_VDI_INVALID) # Class Functions - def vdi_create(self, session, vdi_struct): + def VDI_create(self, session, vdi_struct): sr = XendNode.instance().get_sr() sr_ref = vdi_struct['SR'] if sr.uuid != sr_ref: @@ -1304,11 +1298,11 @@ class XendAPI: vdi_uuid = sr.create_image(vdi_struct) return xen_api_success(vdi_uuid) - def vdi_get_all(self, session): + def VDI_get_all(self, session): sr = XendNode.instance().get_sr() return xen_api_success(sr.list_images()) - def vdi_get_by_name_label(self, session, name): + def VDI_get_by_name_label(self, session, name): sr = XendNode.instance().get_sr() image_uuid = sr.xen_api_get_by_name_label(name) if image_uuid: @@ -1329,7 +1323,7 @@ class XendAPI: VTPM_attr_inst = VTPM_attr_rw # object methods - def vtpm_get_record(self, session, vtpm_ref): + def VTPM_get_record(self, session, vtpm_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: @@ -1346,7 +1340,7 @@ class XendAPI: return xen_api_success(cfg) # Class Functions - def vtpm_get_instance(self, session, vtpm_ref): + def VTPM_get_instance(self, session, vtpm_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: @@ -1360,7 +1354,7 @@ class XendAPI: instance = -1 return xen_api_success(instance) - def vtpm_get_driver(self, session, vtpm_ref): + def VTPM_get_driver(self, session, vtpm_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: @@ -1374,7 +1368,7 @@ class XendAPI: driver = "Unknown" return xen_api_success(driver) - def vtpm_get_backend(self, session, vtpm_ref): + def VTPM_get_backend(self, session, vtpm_ref): xendom = XendDomain.instance() vm = xendom.get_vm_with_dev_uuid('vtpm', vtpm_ref) if not vm: @@ -1388,12 +1382,12 @@ class XendAPI: backend = "Domain-0" return xen_api_success(backend) - def vtpm_get_VM(self, session, vtpm_ref): + def VTPM_get_VM(self, session, vtpm_ref): xendom = XendDomain.instance() return xen_api_success(xendom.get_dev_property('vtpm', vtpm_ref, 'VM')) # class methods - def vtpm_create(self, session, vtpm_struct): + def VTPM_create(self, session, vtpm_struct): xendom = XendDomain.instance() if xendom.is_valid_vm(vtpm_struct['VM']): dom = xendom.get_vm_by_uuid(vtpm_struct['VM']) @@ -1429,32 +1423,30 @@ class XendAPI: SR_funcs = ['get_by_name_label'] # Class Functions - def sr_get_all(self, session): + def SR_get_all(self, session): sr = XendNode.instance().get_sr() return xen_api_success([sr.uuid]) - def sr_get_by_name_label(self, session, label): + def SR_get_by_name_label(self, session, label): sr = XendNode.instance().get_sr() if sr.name_label != label: return xen_api_error(XEND_ERROR_SR_INVALID) return xen_api_success([sr.uuid]) - def sr_create(self, session): + def SR_create(self, session): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def sr_get_by_uuid(self, session): + def SR_get_by_uuid(self, session): return xen_api_success(XendNode.instance().get_sr().uuid) # Class Methods - def sr_clone(self, session, sr_ref): - return xen_api_error(XEND_ERROR_UNSUPPORTED) - def sr_destroy(self, session, sr_ref): + def SR_clone(self, session, sr_ref): return xen_api_error(XEND_ERROR_UNSUPPORTED) - def sr_to_XML(self, session, sr_ref): - return xen_api_todo() + def SR_destroy(self, session, sr_ref): + return xen_api_error(XEND_ERROR_UNSUPPORTED) - def sr_get_record(self, session, sr_ref): + def SR_get_record(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success({ 'uuid': sr.uuid, @@ -1469,44 +1461,44 @@ class XendAPI: }) # Attribute acceess - def sr_get_VDIs(self, session, sr_ref): + def SR_get_VDIs(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.list_images()) - def sr_get_virtual_allocation(self, session, sr_ref): + def SR_get_virtual_allocation(self, session, sr_ref): sr = XendNode.instance().get_sr() return sr.used_space_bytes() - def sr_get_physical_utilisation(self, session, sr_ref): + def SR_get_physical_utilisation(self, session, sr_ref): sr = XendNode.instance().get_sr() return sr.used_space_bytes() - def sr_get_physical_size(self, session, sr_ref): + def SR_get_physical_size(self, session, sr_ref): sr = XendNode.instance().get_sr() return sr.total_space_bytes() - def sr_get_type(self, session, sr_ref): + def SR_get_type(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.type) - def sr_get_location(self, session, sr_ref): + def SR_get_location(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.location) - def sr_get_name_label(self, session, sr_ref): + def SR_get_name_label(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.name_label) - def sr_get_name_description(self, session, sr_ref): + def SR_get_name_description(self, session, sr_ref): sr = XendNode.instance().get_sr() return xen_api_success(sr.name_description) - def sr_set_name_label(self, session, sr_ref, value): + def SR_set_name_label(self, session, sr_ref, value): sr = XendNode.instance().get_sr() sr.name_label = value return xen_api_success_void() - def sr_set_name_description(self, session, sr_ref, value): + def SR_set_name_description(self, session, sr_ref, value): sr = XendNode.instance().get_sr() sr.name_description = value return xen_api_success_void() @@ -1525,24 +1517,24 @@ if __name__ == "__main__": methods = getattr(XendAPI, '%s_methods' % cls, []) funcs = getattr(XendAPI, '%s_funcs' % cls, []) - ref = '%s_ref' % cls.lower() + ref = '%s_ref' % cls for attr_name in ro_attrs + rw_attrs + XendAPI.Base_attr_ro: - getter_name = '%s_get_%s' % (cls.lower(), attr_name.lower()) + getter_name = '%s_get_%s' % (cls, attr_name) output('def %s(self, session, %s):' % (getter_name, ref)) output(' return xen_api_todo()') for attr_name in rw_attrs + XendAPI.Base_attr_rw: - setter_name = '%s_set_%s' % (cls.lower(), attr_name.lower()) + setter_name = '%s_set_%s' % (cls, attr_name) output('def %s(self, session, %s, value):' % (setter_name, ref)) output(' return xen_api_todo()') for method_name in methods + XendAPI.Base_methods: - method_full_name = '%s_%s' % (cls.lower(),method_name.lower()) + method_full_name = '%s_%s' % (cls,method_name) output('def %s(self, session, %s):' % (method_full_name, ref)) output(' return xen_api_todo()') for func_name in funcs + XendAPI.Base_funcs: - func_full_name = '%s_%s' % (cls.lower(), func_name.lower()) + func_full_name = '%s_%s' % (cls, func_name) output('def %s(self, session):' % func_full_name) output(' return xen_api_todo()') From 3c8100f8d9d22f093ac92205a28b745ed3d1c703 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:50:27 +0000 Subject: [PATCH 081/282] [XENAPI] Update debugging scripts to support vbd_list Add function to list all vbds attached to a VM. Update VM config builder to specify the default as 'linux' Signed-off-by: Alastair Tse --- tools/python/scripts/xapi.domcfg.py | 2 +- tools/python/scripts/xapi.py | 38 ++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/tools/python/scripts/xapi.domcfg.py b/tools/python/scripts/xapi.domcfg.py index 8565bd8975..d7b8ae550c 100644 --- a/tools/python/scripts/xapi.domcfg.py +++ b/tools/python/scripts/xapi.domcfg.py @@ -26,7 +26,7 @@ platform_serial = '' platform_localtime = False platform_clock_offset = False platform_enable_audio = False -builder = '' +builder = 'linux' boot_method = '' # this will remove the kernel/initrd ?? kernel_kernel = '/boot/vmlinuz-2.6.16.29-xen' kernel_initrd = '/root/initrd-2.6.16.29-xen.img' diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py index 387ad0a487..7eb96e8945 100644 --- a/tools/python/scripts/xapi.py +++ b/tools/python/scripts/xapi.py @@ -35,11 +35,14 @@ SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \ '%(type)-10s' VDI_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(virtual_size)-8s '\ '%(sector_size)-8s' +VBD_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(VDI)-8s '\ + '%(image)-8s' COMMANDS = { 'host-info': ('', 'Get Xen Host Info'), 'host-set-name': ('', 'Set host name'), 'sr-list': ('', 'List all SRs'), + 'vbd-list': ('', 'List all VBDs'), 'vbd-create': (' [opts]', 'Create VBD attached to domname'), 'vdi-create': (' [opts]', 'Create a VDI'), @@ -165,6 +168,13 @@ def resolve_vm(server, session, vm_name): else: return vm_uuid[0] +def resolve_vdi(server, session, vdi_name): + vdi_uuid = execute(server.VDI.get_by_name_label, session, vdi_name) + if not vdi_uuid: + return None + else: + return vdi_uuid[0] + # # Actual commands # @@ -223,9 +233,9 @@ def xapi_vm_list(*args): for uuid in vm_uuids: vm_info = execute(server.VM.get_record, session, uuid) if is_long: - vbds = vm_info['vbds'] - vifs = vm_info['vifs'] - vtpms = vm_info['vtpms'] + vbds = vm_info['VBDs'] + vifs = vm_info['VIFs'] + vtpms = vm_info['VTPMs'] vif_infos = [] vbd_infos = [] vtpm_infos = [] @@ -238,9 +248,9 @@ def xapi_vm_list(*args): for vtpm in vtpms: vtpm_info = execute(server.VTPM.get_record, session, vtpm) vtpm_infos.append(vtpm_info) - vm_info['vbds'] = vbd_infos - vm_info['vifs'] = vif_infos - vm_info['vtpms'] = vtpm_infos + vm_info['VBDs'] = vbd_infos + vm_info['VIFs'] = vif_infos + vm_info['VTPMs'] = vtpm_infos pprint(vm_info) else: print VM_LIST_FORMAT % _stringify(vm_info) @@ -334,6 +344,22 @@ def xapi_vif_create(*args): vif_uuid = execute(server.VIF.create, session, cfg) print 'Done. (%s)' % vif_uuid +def xapi_vbd_list(*args): + server, session = _connect() + domname = args[0] + + dom_uuid = resolve_vm(server, session, domname) + vbds = execute(server.VM.get_VBDs, session, dom_uuid) + + print VBD_LIST_FORMAT % {'name_label': 'VDI Label', + 'uuid' : 'UUID', + 'VDI': 'VDI', + 'image': 'Image'} + + for vbd in vbds: + vbd_struct = execute(server.VBD.get_record, session, vbd) + print VBD_LIST_FORMAT % vbd_struct + def xapi_vdi_list(*args): server, session = _connect() vdis = execute(server.VDI.get_all, session) From 4b08ed154ca4f746b851cd203d456656a2373397 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:51:46 +0000 Subject: [PATCH 082/282] [XEND] Checks to make sure the image type is valid in configuration The 'builder' (eg. image type) should either be 'hvm' or 'linux' as image.py only supports these at the moment. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index df124c06ca..e4143cc390 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -328,9 +328,14 @@ class XendConfig(dict): raise XendConfigError('Invalid event handling mode: ' + event) + def _builder_sanity_check(self): + if self['builder'] not in ('hvm', 'linux'): + raise XendConfigError('Invalid builder configuration') + def validate(self): self._memory_sanity_check() self._actions_sanity_check() + self._builder_sanity_check() def _dominfo_to_xapi(self, dominfo): self['domid'] = dominfo['domid'] @@ -665,7 +670,14 @@ class XendConfig(dict): officially supported by the Xen API but is required for the rest of Xend to function. """ - pass + + # populate image + self['image']['type'] = self['builder'] + if self['builder'] == 'hvm': + self['image']['hvm'] = {} + for xapi, cfgapi in XENAPI_HVM_CFG.items(): + self['image']['hvm'][cfgapi] = self[xapi] + def _get_old_state_string(self): """Returns the old xm state string. @@ -868,13 +880,14 @@ class XendConfig(dict): elif dev_type in ('vbd', 'tap'): if dev_type == 'vbd': - dev_info['uname'] = cfg_xenapi.get('image', None) + dev_info['uname'] = cfg_xenapi.get('image', '') dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device') elif dev_type == 'tap': dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image') dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device') dev_info['driver'] = cfg_xenapi.get('driver') + dev_info['VDI'] = cfg_xenapi.get('VDI', '') if cfg_xenapi.get('mode') == 'RW': dev_info['mode'] = 'w' From 50453c47bcac45be0d23c803e34caf80031457b9 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 14:53:14 +0000 Subject: [PATCH 083/282] [XEND] Fix Xen API attribute access to be robust to missing keys. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendDomainInfo.py | 30 +++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 9581a9621e..61f7c49192 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1742,13 +1742,13 @@ class XendDomainInfo: return dom_uuid def get_memory_static_max(self): - return self.info['memory_static_max'] + return self.info.get('memory_static_max') def get_memory_static_min(self): - return self.info['memory_static_min'] + return self.info.get('memory_static_min') def get_memory_dynamic_max(self): - return self.info['memory_dynamic_min'] + return self.info.get('memory_dynamic_min') def get_memory_dynamic_min(self): - return self.info['memory_static_min'] + return self.info.get('memory_dynamic_max') def get_vcpus_policy(self): @@ -1766,27 +1766,29 @@ class XendDomainInfo: def get_bios_boot(self): return '' # TODO def get_platform_std_vga(self): - return False + return self.info.get('platform_std_vga', 0) def get_platform_keymap(self): return '' def get_platform_serial(self): - return self.info['platform_serial'] + return self.info.get('platform_serial', '') def get_platform_localtime(self): - return self.info['platform_localtime'] + return self.info.get('platform_localtime', 0) def get_platform_clock_offset(self): - return self.info['platform_clock_offset'] + return self.info.get('platform_clock_offset', 0) def get_platform_enable_audio(self): - return self.info['platform_enable_audio'] + return self.info.get('platform_enable_audio', 0) + def get_platform_keymap(self): + return self.info.get('platform_keymap', '') def get_builder(self): - return self.info['builder'] + return self.info.get('builder', 0) def get_boot_method(self): - return self.info['boot_method'] + return self.info.get('boot_method', '') def get_kernel_image(self): - return self.info['kernel_kernel'] + return self.info.get('kernel_kernel', '') def get_kernel_initrd(self): - return self.info['kernel_initrd'] + return self.info.get('kernel_initrd', '') def get_kernel_args(self): - return self.info['kernel_args'] + return self.info.get('kernel_args', '') def get_grub_cmdline(self): return '' # TODO def get_pci_bus(self): From 16651e108bb69a41a62b6823baf93a540913570f Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 15:19:01 +0000 Subject: [PATCH 084/282] [XEND] Catch TypeErrors when unexpected SXP is encountered. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index e4143cc390..5b54d79c26 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -398,14 +398,14 @@ class XendConfig(dict): for key in extract_keys: val = sxp.child_value(sxp_cfg, key) - if val: + if val != None: try: - try: - cfg[key] = LEGACY_CFG_TYPES[key](val) - except KeyError: - cfg[key] = val - except ValueError: - pass + cfg[key] = LEGACY_CFG_TYPES[key](val) + except KeyError: + cfg[key] = val + except (TypeError, ValueError), e: + log.warn("Unable to parse key %s: %s: %s" % + (key, str(val), e)) # Parsing the device SXP's. In most cases, the SXP looks # like this: @@ -463,7 +463,7 @@ class XendConfig(dict): image_sxp = sxp.child_value(sxp_cfg, 'image', []) if image_sxp: image_vcpus = sxp.child_value(image_sxp, 'vcpus') - if image_vcpus is not None: + if image_vcpus != None: try: if 'vcpus_number' not in cfg: cfg['vcpus_number'] = int(image_vcpus) From c016f643db63b5c0570e45fac5f0be9215742f49 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 30 Nov 2006 15:41:35 +0000 Subject: [PATCH 085/282] [XEND] Fix HVM configuration parsing typo for certain cfg values. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 5b54d79c26..3d79c657c9 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -625,7 +625,7 @@ class XendConfig(dict): self['image'] = image for apikey, imgkey in XENAPI_HVM_CFG.items(): - val = sxp.child(image_sxp, imgkey, None) + val = sxp.child_value(image_sxp, imgkey, None) if val != None: self[apikey] = val @@ -1039,7 +1039,7 @@ class XendConfig(dict): self['image'] = image for apikey, imgkey in XENAPI_HVM_CFG.items(): - val = sxp.child(image_sxp, imgkey, None) + val = sxp.child_value(image_sxp, imgkey, None) if val != None: self[apikey] = val From 96d39d7654812b085d86b09cfe25b805adce4591 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 16:32:24 +0000 Subject: [PATCH 086/282] [XEN] Do not spin at the end of machine_crash_kexec(). If there was no crash image then we should return to the caller who will either restart the machine as normal or continue on as appropriate. Signed-off-by: Ian Campbell --- xen/common/kexec.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/xen/common/kexec.c b/xen/common/kexec.c index ae3f0e6c70..2c4c079314 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -119,8 +119,6 @@ void machine_crash_kexec(void) image = &kexec_image[KEXEC_IMAGE_CRASH_BASE + pos]; machine_kexec(image); /* Does not return */ } - - while (1); /* No image available - just spin */ } static void do_crashdump_trigger(unsigned char key) From cffd8b0db89e6cead31090adf0c96d7d84ee6769 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:07:26 +0000 Subject: [PATCH 087/282] [XEN] Proper segmentation emulation added to HVM emulated PTE writes. Sigmed-off-by: Keir Fraser --- xen/arch/x86/hvm/platform.c | 18 ++-- xen/arch/x86/hvm/svm/emulate.c | 4 +- xen/arch/x86/hvm/svm/svm.c | 98 +++++++++++++-------- xen/arch/x86/hvm/svm/vmcb.c | 22 ++--- xen/arch/x86/hvm/vmx/vmx.c | 134 +++++++++++++++++++++++------ xen/arch/x86/mm.c | 8 +- xen/arch/x86/mm/shadow/common.c | 104 ++++++++++++++++++++-- xen/arch/x86/x86_emulate.c | 32 +++---- xen/include/asm-x86/hvm/hvm.h | 66 ++++++++++---- xen/include/asm-x86/hvm/svm/vmcb.h | 50 +++-------- xen/include/asm-x86/x86_emulate.h | 36 +++++--- 11 files changed, 395 insertions(+), 177 deletions(-) diff --git a/xen/arch/x86/hvm/platform.c b/xen/arch/x86/hvm/platform.c index 46eab76175..a822fc093f 100644 --- a/xen/arch/x86/hvm/platform.c +++ b/xen/arch/x86/hvm/platform.c @@ -920,7 +920,7 @@ void handle_mmio(unsigned long gpa) df = regs->eflags & X86_EFLAGS_DF ? 1 : 0; mode = hvm_guest_x86_mode(v); - inst_addr = hvm_get_segment_base(v, seg_cs) + regs->eip; + inst_addr = hvm_get_segment_base(v, x86_seg_cs) + regs->eip; inst_len = hvm_instruction_length(inst_addr, mode); if ( inst_len <= 0 ) { @@ -964,10 +964,10 @@ void handle_mmio(unsigned long gpa) addr = regs->edi; if ( ad_size == WORD ) addr &= 0xFFFF; - addr += hvm_get_segment_base(v, seg_es); + addr += hvm_get_segment_base(v, x86_seg_es); if ( addr == gpa ) { - enum segment seg; + enum x86_segment seg; dir = IOREQ_WRITE; addr = regs->esi; @@ -975,13 +975,13 @@ void handle_mmio(unsigned long gpa) addr &= 0xFFFF; switch ( seg_sel ) { - case 0x26: seg = seg_es; break; - case 0x2e: seg = seg_cs; break; - case 0x36: seg = seg_ss; break; + case 0x26: seg = x86_seg_es; break; + case 0x2e: seg = x86_seg_cs; break; + case 0x36: seg = x86_seg_ss; break; case 0: - case 0x3e: seg = seg_ds; break; - case 0x64: seg = seg_fs; break; - case 0x65: seg = seg_gs; break; + case 0x3e: seg = x86_seg_ds; break; + case 0x64: seg = x86_seg_fs; break; + case 0x65: seg = x86_seg_gs; break; default: domain_crash_synchronous(); } addr += hvm_get_segment_base(v, seg); diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c index 504bafe7db..c0ea001c82 100644 --- a/xen/arch/x86/hvm/svm/emulate.c +++ b/xen/arch/x86/hvm/svm/emulate.c @@ -209,7 +209,7 @@ unsigned long get_effective_addr_modrm64(struct vmcb_struct *vmcb, #if __x86_64__ /* 64-bit mode */ - if (vmcb->cs.attributes.fields.l && (vmcb->efer & EFER_LMA)) + if (vmcb->cs.attr.fields.l && (vmcb->efer & EFER_LMA)) return vmcb->rip + inst_len + *size + disp; #endif return disp; @@ -334,7 +334,7 @@ unsigned long svm_rip2pointer(struct vmcb_struct *vmcb) * no matter what kind of addressing is used. */ unsigned long p = vmcb->cs.base + vmcb->rip; - if (!(vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA)) + if (!(vmcb->cs.attr.fields.l && vmcb->efer & EFER_LMA)) return (u32)p; /* mask to 32 bits */ /* NB. Should mask to 16 bits if in real mode or 16-bit protected mode. */ return p; diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index a9cc9e9325..9c5393f5f5 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -476,13 +476,13 @@ static int svm_guest_x86_mode(struct vcpu *v) struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; if ( vmcb->efer & EFER_LMA ) - return (vmcb->cs.attributes.fields.l ? + return (vmcb->cs.attr.fields.l ? X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32); if ( svm_realmode(v) ) return X86EMUL_MODE_REAL; - return (vmcb->cs.attributes.fields.db ? + return (vmcb->cs.attr.fields.db ? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16); } @@ -509,31 +509,51 @@ unsigned long svm_get_ctrl_reg(struct vcpu *v, unsigned int num) return 0; /* dummy */ } -static unsigned long svm_get_segment_base(struct vcpu *v, enum segment seg) +static unsigned long svm_get_segment_base(struct vcpu *v, enum x86_segment seg) { struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; int long_mode = 0; #ifdef __x86_64__ - long_mode = vmcb->cs.attributes.fields.l && (vmcb->efer & EFER_LMA); + long_mode = vmcb->cs.attr.fields.l && (vmcb->efer & EFER_LMA); #endif switch ( seg ) { - case seg_cs: return long_mode ? 0 : vmcb->cs.base; - case seg_ds: return long_mode ? 0 : vmcb->ds.base; - case seg_es: return long_mode ? 0 : vmcb->es.base; - case seg_fs: return vmcb->fs.base; - case seg_gs: return vmcb->gs.base; - case seg_ss: return long_mode ? 0 : vmcb->ss.base; - case seg_tr: return vmcb->tr.base; - case seg_gdtr: return vmcb->gdtr.base; - case seg_idtr: return vmcb->idtr.base; - case seg_ldtr: return vmcb->ldtr.base; + case x86_seg_cs: return long_mode ? 0 : vmcb->cs.base; + case x86_seg_ds: return long_mode ? 0 : vmcb->ds.base; + case x86_seg_es: return long_mode ? 0 : vmcb->es.base; + case x86_seg_fs: return vmcb->fs.base; + case x86_seg_gs: return vmcb->gs.base; + case x86_seg_ss: return long_mode ? 0 : vmcb->ss.base; + case x86_seg_tr: return vmcb->tr.base; + case x86_seg_gdtr: return vmcb->gdtr.base; + case x86_seg_idtr: return vmcb->idtr.base; + case x86_seg_ldtr: return vmcb->ldtr.base; } BUG(); return 0; } +static void svm_get_segment_register(struct vcpu *v, enum x86_segment seg, + struct segment_register *reg) +{ + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + switch ( seg ) + { + case x86_seg_cs: memcpy(reg, &vmcb->cs, sizeof(*reg)); break; + case x86_seg_ds: memcpy(reg, &vmcb->ds, sizeof(*reg)); break; + case x86_seg_es: memcpy(reg, &vmcb->es, sizeof(*reg)); break; + case x86_seg_fs: memcpy(reg, &vmcb->fs, sizeof(*reg)); break; + case x86_seg_gs: memcpy(reg, &vmcb->gs, sizeof(*reg)); break; + case x86_seg_ss: memcpy(reg, &vmcb->ss, sizeof(*reg)); break; + case x86_seg_tr: memcpy(reg, &vmcb->tr, sizeof(*reg)); break; + case x86_seg_gdtr: memcpy(reg, &vmcb->gdtr, sizeof(*reg)); break; + case x86_seg_idtr: memcpy(reg, &vmcb->idtr, sizeof(*reg)); break; + case x86_seg_ldtr: memcpy(reg, &vmcb->ldtr, sizeof(*reg)); break; + default: BUG(); + } +} + /* Make sure that xen intercepts any FP accesses from current */ static void svm_stts(struct vcpu *v) { @@ -785,6 +805,11 @@ static void svm_vcpu_destroy(struct vcpu *v) svm_destroy_vmcb(v); } +static void svm_hvm_inject_exception(unsigned int trapnr, int errcode) +{ + svm_inject_exception(current, trapnr, (errcode != -1), errcode); +} + int start_svm(void) { u32 eax, ecx, edx; @@ -844,12 +869,15 @@ int start_svm(void) hvm_funcs.guest_x86_mode = svm_guest_x86_mode; hvm_funcs.get_guest_ctrl_reg = svm_get_ctrl_reg; hvm_funcs.get_segment_base = svm_get_segment_base; + hvm_funcs.get_segment_register = svm_get_segment_register; hvm_funcs.update_host_cr3 = svm_update_host_cr3; hvm_funcs.stts = svm_stts; hvm_funcs.set_tsc_offset = svm_set_tsc_offset; + hvm_funcs.inject_exception = svm_hvm_inject_exception; + hvm_funcs.init_ap_context = svm_init_ap_context; hvm_funcs.init_hypercall_page = svm_init_hypercall_page; @@ -1154,7 +1182,7 @@ static void svm_dr_access(struct vcpu *v, struct cpu_user_regs *regs) static void svm_get_prefix_info( struct vmcb_struct *vmcb, - unsigned int dir, segment_selector_t **seg, unsigned int *asize) + unsigned int dir, svm_segment_register_t **seg, unsigned int *asize) { unsigned char inst[MAX_INST_LEN]; int i; @@ -1235,18 +1263,18 @@ static inline int svm_get_io_address( unsigned long reg; unsigned int asize, isize; int long_mode = 0; - segment_selector_t *seg = NULL; + svm_segment_register_t *seg = NULL; struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; #ifdef __x86_64__ /* If we're in long mode, we shouldn't check the segment presence & limit */ - long_mode = vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA; + long_mode = vmcb->cs.attr.fields.l && vmcb->efer & EFER_LMA; #endif - /* d field of cs.attributes is 1 for 32-bit, 0 for 16 or 64 bit. + /* d field of cs.attr is 1 for 32-bit, 0 for 16 or 64 bit. * l field combined with EFER_LMA -> longmode says whether it's 16 or 64 bit. */ - asize = (long_mode)?64:((vmcb->cs.attributes.fields.db)?32:16); + asize = (long_mode)?64:((vmcb->cs.attr.fields.db)?32:16); /* The ins/outs instructions are single byte, so if we have got more @@ -1266,7 +1294,7 @@ static inline int svm_get_io_address( reg = regs->esi; if (!seg) /* If no prefix, used DS. */ seg = &vmcb->ds; - if (!long_mode && (seg->attributes.fields.type & 0xa) == 0x8) { + if (!long_mode && (seg->attr.fields.type & 0xa) == 0x8) { svm_inject_exception(v, TRAP_gp_fault, 1, 0); return 0; } @@ -1275,14 +1303,14 @@ static inline int svm_get_io_address( { reg = regs->edi; seg = &vmcb->es; /* Note: This is ALWAYS ES. */ - if (!long_mode && (seg->attributes.fields.type & 0xa) != 0x2) { + if (!long_mode && (seg->attr.fields.type & 0xa) != 0x2) { svm_inject_exception(v, TRAP_gp_fault, 1, 0); return 0; } } /* If the segment isn't present, give GP fault! */ - if (!long_mode && !seg->attributes.fields.p) + if (!long_mode && !seg->attr.fields.p) { svm_inject_exception(v, TRAP_gp_fault, 1, 0); return 0; @@ -1305,7 +1333,7 @@ static inline int svm_get_io_address( { ASSERT(*addr == (u32)*addr); if ((u32)(*addr + size - 1) < (u32)*addr || - (seg->attributes.fields.type & 0xc) != 0x4 ? + (seg->attr.fields.type & 0xc) != 0x4 ? *addr + size - 1 > seg->limit : *addr <= seg->limit) { @@ -1318,9 +1346,9 @@ static inline int svm_get_io_address( occur. Note that the checking is not necessary for page granular segments as transfers crossing page boundaries will be broken up anyway. */ - if (!seg->attributes.fields.g && *count > 1) + if (!seg->attr.fields.g && *count > 1) { - if ((seg->attributes.fields.type & 0xc) != 0x4) + if ((seg->attr.fields.type & 0xc) != 0x4) { /* expand-up */ if (!(regs->eflags & EF_DF)) @@ -2154,52 +2182,52 @@ static int svm_do_vmmcall_reset_to_realmode(struct vcpu *v, /* setup the segment registers and all their hidden states */ vmcb->cs.sel = 0xF000; - vmcb->cs.attributes.bytes = 0x089b; + vmcb->cs.attr.bytes = 0x089b; vmcb->cs.limit = 0xffff; vmcb->cs.base = 0x000F0000; vmcb->ss.sel = 0x00; - vmcb->ss.attributes.bytes = 0x0893; + vmcb->ss.attr.bytes = 0x0893; vmcb->ss.limit = 0xffff; vmcb->ss.base = 0x00; vmcb->ds.sel = 0x00; - vmcb->ds.attributes.bytes = 0x0893; + vmcb->ds.attr.bytes = 0x0893; vmcb->ds.limit = 0xffff; vmcb->ds.base = 0x00; vmcb->es.sel = 0x00; - vmcb->es.attributes.bytes = 0x0893; + vmcb->es.attr.bytes = 0x0893; vmcb->es.limit = 0xffff; vmcb->es.base = 0x00; vmcb->fs.sel = 0x00; - vmcb->fs.attributes.bytes = 0x0893; + vmcb->fs.attr.bytes = 0x0893; vmcb->fs.limit = 0xffff; vmcb->fs.base = 0x00; vmcb->gs.sel = 0x00; - vmcb->gs.attributes.bytes = 0x0893; + vmcb->gs.attr.bytes = 0x0893; vmcb->gs.limit = 0xffff; vmcb->gs.base = 0x00; vmcb->ldtr.sel = 0x00; - vmcb->ldtr.attributes.bytes = 0x0000; + vmcb->ldtr.attr.bytes = 0x0000; vmcb->ldtr.limit = 0x0; vmcb->ldtr.base = 0x00; vmcb->gdtr.sel = 0x00; - vmcb->gdtr.attributes.bytes = 0x0000; + vmcb->gdtr.attr.bytes = 0x0000; vmcb->gdtr.limit = 0x0; vmcb->gdtr.base = 0x00; vmcb->tr.sel = 0; - vmcb->tr.attributes.bytes = 0; + vmcb->tr.attr.bytes = 0; vmcb->tr.limit = 0x0; vmcb->tr.base = 0; vmcb->idtr.sel = 0x00; - vmcb->idtr.attributes.bytes = 0x0000; + vmcb->idtr.attr.bytes = 0x0000; vmcb->idtr.limit = 0x3ff; vmcb->idtr.base = 0x00; diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c index f00372440e..b32db1b62c 100644 --- a/xen/arch/x86/hvm/svm/vmcb.c +++ b/xen/arch/x86/hvm/svm/vmcb.c @@ -90,7 +90,7 @@ static int construct_vmcb(struct vcpu *v) { struct arch_svm_struct *arch_svm = &v->arch.hvm_svm; struct vmcb_struct *vmcb = arch_svm->vmcb; - segment_attributes_t attrib; + svm_segment_attributes_t attrib; /* Always flush the TLB on VMRUN. */ vmcb->tlb_control = 1; @@ -166,13 +166,13 @@ static int construct_vmcb(struct vcpu *v) attrib.fields.p = 1; /* segment present */ attrib.fields.db = 1; /* 32-bit */ attrib.fields.g = 1; /* 4K pages in limit */ - vmcb->es.attributes = attrib; - vmcb->ss.attributes = attrib; - vmcb->ds.attributes = attrib; - vmcb->fs.attributes = attrib; - vmcb->gs.attributes = attrib; + vmcb->es.attr = attrib; + vmcb->ss.attr = attrib; + vmcb->ds.attr = attrib; + vmcb->fs.attr = attrib; + vmcb->gs.attr = attrib; attrib.fields.type = 0xb; /* type=0xb -> executable/readable, accessed */ - vmcb->cs.attributes = attrib; + vmcb->cs.attr = attrib; /* Guest IDT. */ vmcb->idtr.base = 0; @@ -186,11 +186,11 @@ static int construct_vmcb(struct vcpu *v) vmcb->ldtr.sel = 0; vmcb->ldtr.base = 0; vmcb->ldtr.limit = 0; - vmcb->ldtr.attributes.bytes = 0; + vmcb->ldtr.attr.bytes = 0; /* Guest TSS. */ attrib.fields.type = 0xb; /* 32-bit TSS (busy) */ - vmcb->tr.attributes = attrib; + vmcb->tr.attr = attrib; vmcb->tr.base = 0; vmcb->tr.limit = 0xff; @@ -278,10 +278,10 @@ void svm_do_launch(struct vcpu *v) v->arch.schedule_tail = arch_svm_do_resume; } -static void svm_dump_sel(char *name, segment_selector_t *s) +static void svm_dump_sel(char *name, svm_segment_register_t *s) { printk("%s: sel=0x%04x, attr=0x%04x, limit=0x%08x, base=0x%016llx\n", - name, s->sel, s->attributes.bytes, s->limit, + name, s->sel, s->attr.bytes, s->limit, (unsigned long long)s->base); } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 7ccd218f53..6a1f70a79d 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -501,7 +501,7 @@ static unsigned long vmx_get_ctrl_reg(struct vcpu *v, unsigned int num) return 0; /* dummy */ } -static unsigned long vmx_get_segment_base(struct vcpu *v, enum segment seg) +static unsigned long vmx_get_segment_base(struct vcpu *v, enum x86_segment seg) { unsigned long base = 0; int long_mode = 0; @@ -516,22 +516,94 @@ static unsigned long vmx_get_segment_base(struct vcpu *v, enum segment seg) switch ( seg ) { - case seg_cs: if ( !long_mode ) base = __vmread(GUEST_CS_BASE); break; - case seg_ds: if ( !long_mode ) base = __vmread(GUEST_DS_BASE); break; - case seg_es: if ( !long_mode ) base = __vmread(GUEST_ES_BASE); break; - case seg_fs: base = __vmread(GUEST_FS_BASE); break; - case seg_gs: base = __vmread(GUEST_GS_BASE); break; - case seg_ss: if ( !long_mode ) base = __vmread(GUEST_SS_BASE); break; - case seg_tr: base = __vmread(GUEST_TR_BASE); break; - case seg_gdtr: base = __vmread(GUEST_GDTR_BASE); break; - case seg_idtr: base = __vmread(GUEST_IDTR_BASE); break; - case seg_ldtr: base = __vmread(GUEST_LDTR_BASE); break; + case x86_seg_cs: if ( !long_mode ) base = __vmread(GUEST_CS_BASE); break; + case x86_seg_ds: if ( !long_mode ) base = __vmread(GUEST_DS_BASE); break; + case x86_seg_es: if ( !long_mode ) base = __vmread(GUEST_ES_BASE); break; + case x86_seg_fs: base = __vmread(GUEST_FS_BASE); break; + case x86_seg_gs: base = __vmread(GUEST_GS_BASE); break; + case x86_seg_ss: if ( !long_mode ) base = __vmread(GUEST_SS_BASE); break; + case x86_seg_tr: base = __vmread(GUEST_TR_BASE); break; + case x86_seg_gdtr: base = __vmread(GUEST_GDTR_BASE); break; + case x86_seg_idtr: base = __vmread(GUEST_IDTR_BASE); break; + case x86_seg_ldtr: base = __vmread(GUEST_LDTR_BASE); break; default: BUG(); break; } return base; } +static void vmx_get_segment_register(struct vcpu *v, enum x86_segment seg, + struct segment_register *reg) +{ + u16 attr = 0; + + ASSERT(v == current); + + switch ( seg ) + { + case x86_seg_cs: + reg->sel = __vmread(GUEST_CS_SELECTOR); + reg->limit = __vmread(GUEST_CS_LIMIT); + reg->base = __vmread(GUEST_CS_BASE); + attr = __vmread(GUEST_CS_AR_BYTES); + break; + case x86_seg_ds: + reg->sel = __vmread(GUEST_DS_SELECTOR); + reg->limit = __vmread(GUEST_DS_LIMIT); + reg->base = __vmread(GUEST_DS_BASE); + attr = __vmread(GUEST_DS_AR_BYTES); + break; + case x86_seg_es: + reg->sel = __vmread(GUEST_ES_SELECTOR); + reg->limit = __vmread(GUEST_ES_LIMIT); + reg->base = __vmread(GUEST_ES_BASE); + attr = __vmread(GUEST_ES_AR_BYTES); + break; + case x86_seg_fs: + reg->sel = __vmread(GUEST_FS_SELECTOR); + reg->limit = __vmread(GUEST_FS_LIMIT); + reg->base = __vmread(GUEST_FS_BASE); + attr = __vmread(GUEST_FS_AR_BYTES); + break; + case x86_seg_gs: + reg->sel = __vmread(GUEST_GS_SELECTOR); + reg->limit = __vmread(GUEST_GS_LIMIT); + reg->base = __vmread(GUEST_GS_BASE); + attr = __vmread(GUEST_GS_AR_BYTES); + break; + case x86_seg_ss: + reg->sel = __vmread(GUEST_SS_SELECTOR); + reg->limit = __vmread(GUEST_SS_LIMIT); + reg->base = __vmread(GUEST_SS_BASE); + attr = __vmread(GUEST_SS_AR_BYTES); + break; + case x86_seg_tr: + reg->sel = __vmread(GUEST_TR_SELECTOR); + reg->limit = __vmread(GUEST_TR_LIMIT); + reg->base = __vmread(GUEST_TR_BASE); + attr = __vmread(GUEST_TR_AR_BYTES); + break; + case x86_seg_gdtr: + reg->limit = __vmread(GUEST_GDTR_LIMIT); + reg->base = __vmread(GUEST_GDTR_BASE); + break; + case x86_seg_idtr: + reg->limit = __vmread(GUEST_IDTR_LIMIT); + reg->base = __vmread(GUEST_IDTR_BASE); + break; + case x86_seg_ldtr: + reg->sel = __vmread(GUEST_LDTR_SELECTOR); + reg->limit = __vmread(GUEST_LDTR_LIMIT); + reg->base = __vmread(GUEST_LDTR_BASE); + attr = __vmread(GUEST_LDTR_AR_BYTES); + break; + default: + BUG(); + } + + reg->attr.bytes = (attr & 0xff) | ((attr >> 4) & 0xf00); +} + /* Make sure that xen intercepts any FP accesses from current */ static void vmx_stts(struct vcpu *v) { @@ -630,6 +702,11 @@ static int vmx_pae_enabled(struct vcpu *v) return (vmx_paging_enabled(v) && (cr4 & X86_CR4_PAE)); } +static void vmx_inject_exception(unsigned int trapnr, int errcode) +{ + vmx_inject_hw_exception(current, trapnr, errcode); +} + /* Setup HVM interfaces */ static void vmx_setup_hvm_funcs(void) { @@ -650,12 +727,15 @@ static void vmx_setup_hvm_funcs(void) hvm_funcs.guest_x86_mode = vmx_guest_x86_mode; hvm_funcs.get_guest_ctrl_reg = vmx_get_ctrl_reg; hvm_funcs.get_segment_base = vmx_get_segment_base; + hvm_funcs.get_segment_register = vmx_get_segment_register; hvm_funcs.update_host_cr3 = vmx_update_host_cr3; hvm_funcs.stts = vmx_stts; hvm_funcs.set_tsc_offset = vmx_set_tsc_offset; + hvm_funcs.inject_exception = vmx_inject_exception; + hvm_funcs.init_ap_context = vmx_init_ap_context; hvm_funcs.init_hypercall_page = vmx_init_hypercall_page; @@ -962,14 +1042,14 @@ static void vmx_do_invlpg(unsigned long va) static int vmx_check_descriptor(int long_mode, unsigned long eip, int inst_len, - enum segment seg, unsigned long *base, + enum x86_segment seg, unsigned long *base, u32 *limit, u32 *ar_bytes) { enum vmcs_field ar_field, base_field, limit_field; *base = 0; *limit = 0; - if ( seg != seg_es ) + if ( seg != x86_seg_es ) { unsigned char inst[MAX_INST_LEN]; int i; @@ -999,22 +1079,22 @@ static int vmx_check_descriptor(int long_mode, unsigned long eip, int inst_len, #endif continue; case 0x2e: /* CS */ - seg = seg_cs; + seg = x86_seg_cs; continue; case 0x36: /* SS */ - seg = seg_ss; + seg = x86_seg_ss; continue; case 0x26: /* ES */ - seg = seg_es; + seg = x86_seg_es; continue; case 0x64: /* FS */ - seg = seg_fs; + seg = x86_seg_fs; continue; case 0x65: /* GS */ - seg = seg_gs; + seg = x86_seg_gs; continue; case 0x3e: /* DS */ - seg = seg_ds; + seg = x86_seg_ds; continue; } } @@ -1022,32 +1102,32 @@ static int vmx_check_descriptor(int long_mode, unsigned long eip, int inst_len, switch ( seg ) { - case seg_cs: + case x86_seg_cs: ar_field = GUEST_CS_AR_BYTES; base_field = GUEST_CS_BASE; limit_field = GUEST_CS_LIMIT; break; - case seg_ds: + case x86_seg_ds: ar_field = GUEST_DS_AR_BYTES; base_field = GUEST_DS_BASE; limit_field = GUEST_DS_LIMIT; break; - case seg_es: + case x86_seg_es: ar_field = GUEST_ES_AR_BYTES; base_field = GUEST_ES_BASE; limit_field = GUEST_ES_LIMIT; break; - case seg_fs: + case x86_seg_fs: ar_field = GUEST_FS_AR_BYTES; base_field = GUEST_FS_BASE; limit_field = GUEST_FS_LIMIT; break; - case seg_gs: + case x86_seg_gs: ar_field = GUEST_FS_AR_BYTES; base_field = GUEST_FS_BASE; limit_field = GUEST_FS_LIMIT; break; - case seg_ss: + case x86_seg_ss: ar_field = GUEST_GS_AR_BYTES; base_field = GUEST_GS_BASE; limit_field = GUEST_GS_LIMIT; @@ -1057,7 +1137,7 @@ static int vmx_check_descriptor(int long_mode, unsigned long eip, int inst_len, return 0; } - if ( !long_mode || seg == seg_fs || seg == seg_gs ) + if ( !long_mode || seg == x86_seg_fs || seg == x86_seg_gs ) { *base = __vmread(base_field); *limit = __vmread(limit_field); @@ -1127,7 +1207,7 @@ static void vmx_io_instruction(unsigned long exit_qualification, * selector is null. */ if ( !vmx_check_descriptor(long_mode, regs->eip, inst_len, - dir == IOREQ_WRITE ? seg_ds : seg_es, + dir==IOREQ_WRITE ? x86_seg_ds : x86_seg_es, &base, &limit, &ar_bytes) ) { if ( !long_mode ) { vmx_inject_hw_exception(current, TRAP_gp_fault, 0); diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 24a43663ae..47fb500fc6 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3040,7 +3040,7 @@ struct ptwr_emulate_ctxt { }; static int ptwr_emulated_read( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long *val, unsigned int bytes, @@ -3183,7 +3183,7 @@ static int ptwr_emulated_update( } static int ptwr_emulated_write( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long val, unsigned int bytes, @@ -3195,7 +3195,7 @@ static int ptwr_emulated_write( } static int ptwr_emulated_cmpxchg( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long old, unsigned long new, @@ -3208,7 +3208,7 @@ static int ptwr_emulated_cmpxchg( } static int ptwr_emulated_cmpxchg8b( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long old, unsigned long old_hi, diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 539f81f947..8bf43133e4 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -69,14 +69,87 @@ int _shadow_mode_refcounts(struct domain *d) /* x86 emulator support for the shadow code */ +static int hvm_translate_linear_addr( + enum x86_segment seg, + unsigned long offset, + unsigned int bytes, + unsigned int is_write, + unsigned long *paddr) +{ + struct segment_register creg, dreg; + unsigned long limit, addr = offset; + uint32_t last_byte; + + hvm_get_segment_register(current, x86_seg_cs, &creg); + hvm_get_segment_register(current, seg, &dreg); + + if ( !creg.attr.fields.l || !hvm_long_mode_enabled(current) ) + { + /* + * COMPATIBILITY MODE: Apply segment checks and add base. + */ + + /* If this is a store, is the segment a writable data segment? */ + if ( is_write && ((dreg.attr.fields.type & 0xa) != 0x2) ) + goto gpf; + + /* Calculate the segment limit, including granularity flag. */ + limit = dreg.limit; + if ( dreg.attr.fields.g ) + limit = (limit << 12) | 0xfff; + + last_byte = offset + bytes - 1; + + /* Is this a grows-down data segment? Special limit check if so. */ + if ( (dreg.attr.fields.type & 0xc) == 0x4 ) + { + /* Is upper limit 0xFFFF or 0xFFFFFFFF? */ + if ( !dreg.attr.fields.db ) + last_byte = (uint16_t)last_byte; + + /* Check first byte and last byte against respective bounds. */ + if ( (offset <= limit) || (last_byte < offset) ) + goto gpf; + } + else if ( (last_byte > limit) || (last_byte < offset) ) + goto gpf; /* last byte is beyond limit or wraps 0xFFFFFFFF */ + + /* + * Hardware truncates to 32 bits in compatibility mode. + * It does not truncate to 16 bits in 16-bit address-size mode. + */ + addr = (uint32_t)(addr + dreg.base); + } + else if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) ) + { + /* + * LONG MODE: FS and GS add a segment base. + */ + addr += dreg.base; + } + + *paddr = addr; + return 0; + + gpf: + /* Inject #GP(0). */ + hvm_inject_exception(TRAP_gp_fault, 0); + return X86EMUL_PROPAGATE_FAULT; +} + static int -sh_x86_emulate_read(unsigned int seg, +sh_x86_emulate_read(enum x86_segment seg, unsigned long offset, unsigned long *val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { - unsigned long addr = offset; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr(seg, offset, bytes, 0, &addr); + if ( rc ) + return rc; *val = 0; // XXX -- this is WRONG. @@ -102,14 +175,19 @@ sh_x86_emulate_read(unsigned int seg, } static int -sh_x86_emulate_write(unsigned int seg, +sh_x86_emulate_write(enum x86_segment seg, unsigned long offset, unsigned long val, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { struct vcpu *v = current; - unsigned long addr = offset; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr(seg, offset, bytes, 1, &addr); + if ( rc ) + return rc; #if 0 SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n", @@ -119,7 +197,7 @@ sh_x86_emulate_write(unsigned int seg, } static int -sh_x86_emulate_cmpxchg(unsigned int seg, +sh_x86_emulate_cmpxchg(enum x86_segment seg, unsigned long offset, unsigned long old, unsigned long new, @@ -127,7 +205,12 @@ sh_x86_emulate_cmpxchg(unsigned int seg, struct x86_emulate_ctxt *ctxt) { struct vcpu *v = current; - unsigned long addr = offset; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr(seg, offset, bytes, 1, &addr); + if ( rc ) + return rc; #if 0 SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n", @@ -138,7 +221,7 @@ sh_x86_emulate_cmpxchg(unsigned int seg, } static int -sh_x86_emulate_cmpxchg8b(unsigned int seg, +sh_x86_emulate_cmpxchg8b(enum x86_segment seg, unsigned long offset, unsigned long old_lo, unsigned long old_hi, @@ -147,7 +230,12 @@ sh_x86_emulate_cmpxchg8b(unsigned int seg, struct x86_emulate_ctxt *ctxt) { struct vcpu *v = current; - unsigned long addr = offset; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr(seg, offset, 8, 1, &addr); + if ( rc ) + return rc; #if 0 SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx:%lx n:=%#lx:%lx\n", diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 18921846ee..555655f83a 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -199,8 +199,8 @@ struct operand { /* OP_REG: Pointer to register field. */ unsigned long *reg; /* OP_MEM: Segment and offset. */ - unsigned int mem_seg; - unsigned long mem_off; + enum x86_segment mem_seg; + unsigned long mem_off; }; /* EFLAGS bit definitions. */ @@ -375,7 +375,7 @@ do{ __asm__ __volatile__ ( \ /* Fetch next part of the instruction being emulated. */ #define _insn_fetch(_size) \ ({ unsigned long _x; \ - rc = ops->read(_regs.cs, _regs.eip, &_x, (_size), ctxt); \ + rc = ops->read(x86_seg_cs, _regs.eip, &_x, (_size), ctxt); \ if ( rc != 0 ) \ goto done; \ _regs.eip += (_size); \ @@ -452,7 +452,7 @@ dump_instr( dprintf("Instr:"); for ( i = 0; i < 16; i++, eip++ ) { - if ( ops->read(ctxt->regs->cs, eip, &x, 1, ctxt) != 0 ) + if ( ops->read(x86_seg_cs, eip, &x, 1, ctxt) != 0 ) printk(" ??"); else printk(" %02x", (uint8_t)x); @@ -476,8 +476,8 @@ x86_emulate_memop( struct operand src, dst; int mode = ctxt->mode; - unsigned int ea_seg = X86_SEG_DS; - unsigned long ea_off = 0; + enum x86_segment ea_seg = x86_seg_ds; + unsigned long ea_off = 0; switch ( mode ) { @@ -513,22 +513,22 @@ x86_emulate_memop( ad_bytes ^= 6; /* switch between 2/4 bytes */ break; case 0x2e: /* CS override */ - ea_seg = X86_SEG_CS; + ea_seg = x86_seg_cs; break; case 0x3e: /* DS override */ - ea_seg = X86_SEG_DS; + ea_seg = x86_seg_ds; break; case 0x26: /* ES override */ - ea_seg = X86_SEG_ES; + ea_seg = x86_seg_es; break; case 0x64: /* FS override */ - ea_seg = X86_SEG_FS; + ea_seg = x86_seg_fs; break; case 0x65: /* GS override */ - ea_seg = X86_SEG_GS; + ea_seg = x86_seg_gs; break; case 0x36: /* SS override */ - ea_seg = X86_SEG_SS; + ea_seg = x86_seg_ss; break; case 0xf0: /* LOCK */ lock_prefix = 1; @@ -860,7 +860,7 @@ x86_emulate_memop( /* 64-bit mode: POP always pops a 64-bit operand. */ if ( mode == X86EMUL_MODE_PROT64 ) dst.bytes = 8; - if ( (rc = ops->read(X86_SEG_SS, truncate_ea(_regs.esp), + if ( (rc = ops->read(x86_seg_ss, truncate_ea(_regs.esp), &dst.val, dst.bytes, ctxt)) != 0 ) goto done; register_address_increment(_regs.esp, dst.bytes); @@ -942,7 +942,7 @@ x86_emulate_memop( goto done; } register_address_increment(_regs.esp, -dst.bytes); - if ( (rc = ops->write(X86_SEG_SS, truncate_ea(_regs.esp), + if ( (rc = ops->write(x86_seg_ss, truncate_ea(_regs.esp), dst.val, dst.bytes, ctxt)) != 0 ) goto done; dst.val = dst.orig_val; /* skanky: disable writeback */ @@ -1024,7 +1024,7 @@ x86_emulate_memop( case 0xa4 ... 0xa5: /* movs */ dst.type = OP_MEM; dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.mem_seg = X86_SEG_ES; + dst.mem_seg = x86_seg_es; dst.mem_off = truncate_ea(_regs.edi); if ( (rc = ops->read(ea_seg, truncate_ea(_regs.esi), &dst.val, dst.bytes, ctxt)) != 0 ) @@ -1037,7 +1037,7 @@ x86_emulate_memop( case 0xaa ... 0xab: /* stos */ dst.type = OP_MEM; dst.bytes = (d & ByteOp) ? 1 : op_bytes; - dst.mem_seg = X86_SEG_ES; + dst.mem_seg = x86_seg_es; dst.mem_off = truncate_ea(_regs.edi); dst.val = _regs.eax; register_address_increment( diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 83ebf48805..aafeecf3df 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -17,28 +17,47 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */ + #ifndef __ASM_X86_HVM_HVM_H__ #define __ASM_X86_HVM_HVM_H__ -enum segment { - seg_cs, - seg_ss, - seg_ds, - seg_es, - seg_fs, - seg_gs, - seg_tr, - seg_ldtr, - seg_gdtr, - seg_idtr -}; +#include + +/* + * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the + * segment descriptor. It happens to match the format of an AMD SVM VMCB. + */ +typedef union segment_attributes { + u16 bytes; + struct + { + u16 type:4; /* 0; Bit 40-43 */ + u16 s: 1; /* 4; Bit 44 */ + u16 dpl: 2; /* 5; Bit 45-46 */ + u16 p: 1; /* 7; Bit 47 */ + u16 avl: 1; /* 8; Bit 52 */ + u16 l: 1; /* 9; Bit 53 */ + u16 db: 1; /* 10; Bit 54 */ + u16 g: 1; /* 11; Bit 55 */ + } fields; +} __attribute__ ((packed)) segment_attributes_t; + +/* + * Full state of a segment register (visible and hidden portions). + * Again, this happens to match the format of an AMD SVM VMCB. + */ +typedef struct segment_register { + u16 sel; + segment_attributes_t attr; + u32 limit; + u64 base; +} __attribute__ ((packed)) segment_register_t; /* * The hardware virtual machine (HVM) interface abstracts away from the * x86/x86_64 CPU virtualization assist specifics. Currently this interface * supports Intel's VT-x and AMD's SVM extensions. */ - struct hvm_function_table { /* * Disable HVM functionality @@ -74,7 +93,9 @@ struct hvm_function_table { int (*pae_enabled)(struct vcpu *v); int (*guest_x86_mode)(struct vcpu *v); unsigned long (*get_guest_ctrl_reg)(struct vcpu *v, unsigned int num); - unsigned long (*get_segment_base)(struct vcpu *v, enum segment seg); + unsigned long (*get_segment_base)(struct vcpu *v, enum x86_segment seg); + void (*get_segment_register)(struct vcpu *v, enum x86_segment seg, + struct segment_register *reg); /* * Re-set the value of CR3 that Xen runs on when handling VM exits @@ -89,6 +110,8 @@ struct hvm_function_table { void (*stts)(struct vcpu *v); void (*set_tsc_offset)(struct vcpu *v, u64 offset); + void (*inject_exception)(unsigned int trapnr, int errcode); + void (*init_ap_context)(struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector); @@ -172,11 +195,18 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, unsigned int num) } static inline unsigned long -hvm_get_segment_base(struct vcpu *v, enum segment seg) +hvm_get_segment_base(struct vcpu *v, enum x86_segment seg) { return hvm_funcs.get_segment_base(v, seg); } +static inline void +hvm_get_segment_register(struct vcpu *v, enum x86_segment seg, + struct segment_register *reg) +{ + hvm_funcs.get_segment_register(v, seg, reg); +} + void hvm_stts(struct vcpu *v); void hvm_set_guest_time(struct vcpu *v, u64 gtime); void hvm_freeze_time(struct vcpu *v); @@ -190,6 +220,12 @@ hvm_init_ap_context(struct vcpu_guest_context *ctxt, return hvm_funcs.init_ap_context(ctxt, vcpuid, trampoline_vector); } +static inline void +hvm_inject_exception(unsigned int trapnr, int errcode) +{ + hvm_funcs.inject_exception(trapnr, errcode); +} + int hvm_bringup_ap(int vcpuid, int trampoline_vector); #endif /* __ASM_X86_HVM_HVM_H__ */ diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h index 2d6a4ed0f3..81d41ea688 100644 --- a/xen/include/asm-x86/hvm/svm/vmcb.h +++ b/xen/include/asm-x86/hvm/svm/vmcb.h @@ -311,33 +311,9 @@ enum { SVM_CPU_STATE_ASSIST_ENABLED, }; -/* - * Attribute for segment selector. This is a copy of bit 40:47 & 52:55 of the - * segment descriptor. - */ -typedef union -{ - u16 bytes; - struct - { - u16 type:4; /* 0; Bit 40-43 */ - u16 s: 1; /* 4; Bit 44 */ - u16 dpl: 2; /* 5; Bit 45-46 */ - u16 p: 1; /* 7; Bit 47 */ - u16 avl: 1; /* 8; Bit 52 */ - u16 l: 1; /* 9; Bit 53 */ - u16 db: 1; /* 10; Bit 54 */ - u16 g: 1; /* 11; Bit 55 */ - } fields; -} __attribute__ ((packed)) segment_attributes_t; - -typedef struct -{ - u16 sel; - segment_attributes_t attributes; - u32 limit; - u64 base; -} __attribute__ ((packed)) segment_selector_t; +/* Definitions of segment state are borrowed by the generic HVM code. */ +typedef segment_attributes_t svm_segment_attributes_t; +typedef segment_register_t svm_segment_register_t; typedef union { @@ -426,16 +402,16 @@ struct vmcb_struct { u64 h_cr3; /* offset 0xB0 */ u64 res09[105]; /* offset 0xB8 pad to save area */ - segment_selector_t es; /* offset 1024 */ - segment_selector_t cs; - segment_selector_t ss; - segment_selector_t ds; - segment_selector_t fs; - segment_selector_t gs; - segment_selector_t gdtr; - segment_selector_t ldtr; - segment_selector_t idtr; - segment_selector_t tr; + svm_segment_register_t es; /* offset 1024 */ + svm_segment_register_t cs; + svm_segment_register_t ss; + svm_segment_register_t ds; + svm_segment_register_t fs; + svm_segment_register_t gs; + svm_segment_register_t gdtr; + svm_segment_register_t ldtr; + svm_segment_register_t idtr; + svm_segment_register_t tr; u64 res10[5]; u8 res11[3]; u8 cpl; diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h index 4bc49c5487..ef23291cdc 100644 --- a/xen/include/asm-x86/x86_emulate.h +++ b/xen/include/asm-x86/x86_emulate.h @@ -11,16 +11,26 @@ struct x86_emulate_ctxt; -#define X86_SEG_CS 0 -#define X86_SEG_SS 1 -#define X86_SEG_DS 2 -#define X86_SEG_ES 3 -#define X86_SEG_FS 4 -#define X86_SEG_GS 5 +/* + * Comprehensive enumeration of x86 segment registers. Note that the system + * registers (TR, LDTR, GDTR, IDTR) are never referenced by the emulator. + */ +enum x86_segment { + /* General purpose. */ + x86_seg_cs, + x86_seg_ss, + x86_seg_ds, + x86_seg_es, + x86_seg_fs, + x86_seg_gs, + /* System. */ + x86_seg_tr, + x86_seg_ldtr, + x86_seg_gdtr, + x86_seg_idtr +}; /* - * x86_emulate_ops: - * * These operations represent the instruction emulator's interface to memory. * * NOTES: @@ -45,7 +55,7 @@ struct x86_emulate_ops { /* * All functions: - * @seg: [IN ] Segment being dereferenced (specified as X86_SEG_??). + * @seg: [IN ] Segment being dereferenced (specified as x86_seg_??). * @offset [IN ] Offset within segment. */ @@ -55,7 +65,7 @@ struct x86_emulate_ops * @bytes: [IN ] Number of bytes to read from memory. */ int (*read)( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long *val, unsigned int bytes, @@ -67,7 +77,7 @@ struct x86_emulate_ops * @bytes: [IN ] Number of bytes to write to memory. */ int (*write)( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long val, unsigned int bytes, @@ -80,7 +90,7 @@ struct x86_emulate_ops * @bytes: [IN ] Number of bytes to access using CMPXCHG. */ int (*cmpxchg)( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long old, unsigned long new, @@ -98,7 +108,7 @@ struct x86_emulate_ops * to defining a function that always returns X86EMUL_UNHANDLEABLE. */ int (*cmpxchg8b)( - unsigned int seg, + enum x86_segment seg, unsigned long offset, unsigned long old_lo, unsigned long old_hi, From f446b44935ec9e42dba073dccffec738a5feaa37 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:14:09 +0000 Subject: [PATCH 088/282] [XEN] Arch-specific softirq definitions. Signed-off-by: Alex Williamson --- xen/include/asm-ia64/softirq.h | 6 ++++++ xen/include/asm-powerpc/softirq.h | 6 ++++++ xen/include/asm-x86/softirq.h | 6 ++++++ xen/include/xen/softirq.h | 7 ++++++- 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 xen/include/asm-ia64/softirq.h create mode 100644 xen/include/asm-powerpc/softirq.h create mode 100644 xen/include/asm-x86/softirq.h diff --git a/xen/include/asm-ia64/softirq.h b/xen/include/asm-ia64/softirq.h new file mode 100644 index 0000000000..3444d300c0 --- /dev/null +++ b/xen/include/asm-ia64/softirq.h @@ -0,0 +1,6 @@ +#ifndef __ASM_SOFTIRQ_H__ +#define __ASM_SOFTIRQ_H__ + +#define NR_ARCH_SOFTIRQS 0 + +#endif /* __ASM_SOFTIRQ_H__ */ diff --git a/xen/include/asm-powerpc/softirq.h b/xen/include/asm-powerpc/softirq.h new file mode 100644 index 0000000000..3444d300c0 --- /dev/null +++ b/xen/include/asm-powerpc/softirq.h @@ -0,0 +1,6 @@ +#ifndef __ASM_SOFTIRQ_H__ +#define __ASM_SOFTIRQ_H__ + +#define NR_ARCH_SOFTIRQS 0 + +#endif /* __ASM_SOFTIRQ_H__ */ diff --git a/xen/include/asm-x86/softirq.h b/xen/include/asm-x86/softirq.h new file mode 100644 index 0000000000..3444d300c0 --- /dev/null +++ b/xen/include/asm-x86/softirq.h @@ -0,0 +1,6 @@ +#ifndef __ASM_SOFTIRQ_H__ +#define __ASM_SOFTIRQ_H__ + +#define NR_ARCH_SOFTIRQS 0 + +#endif /* __ASM_SOFTIRQ_H__ */ diff --git a/xen/include/xen/softirq.h b/xen/include/xen/softirq.h index d4e8edd7ad..a51aad6280 100644 --- a/xen/include/xen/softirq.h +++ b/xen/include/xen/softirq.h @@ -9,7 +9,12 @@ #define NMI_SOFTIRQ 4 #define PAGE_SCRUB_SOFTIRQ 5 #define TRACE_SOFTIRQ 6 -#define NR_SOFTIRQS 7 + +#define NR_COMMON_SOFTIRQS 7 + +#include + +#define NR_SOFTIRQS (NR_COMMON_SOFTIRQS + NR_ARCH_SOFTIRQS) #ifndef __ASSEMBLY__ From 89f64447946ccfaa906987c3ce72ab3788c5705d Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:17:28 +0000 Subject: [PATCH 089/282] [MINIOS] Improved unbind_all_ports(). Signed-off-by: Jacob Gorm Hansen --- extras/mini-os/events.c | 27 +++++++++++++++------------ extras/mini-os/include/events.h | 1 + 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/extras/mini-os/events.c b/extras/mini-os/events.c index 5d60ab70fc..dad8e42377 100644 --- a/extras/mini-os/events.c +++ b/extras/mini-os/events.c @@ -31,26 +31,27 @@ typedef struct _ev_action_t { u32 count; } ev_action_t; - static ev_action_t ev_actions[NR_EVS]; void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data); +static unsigned long bound_ports[NR_EVS/(8*sizeof(unsigned long))]; + void unbind_all_ports(void) { int i; - for(i=0;i Date: Thu, 30 Nov 2006 17:21:52 +0000 Subject: [PATCH 090/282] linux/x86-64: missing agp.h This causes data corruption and/or crashes when AGP is actually used. Signed-off-by: Jan Beulich --- .../include/asm-x86_64/mach-xen/asm/agp.h | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/agp.h diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/agp.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/agp.h new file mode 100644 index 0000000000..60c12a8b71 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/agp.h @@ -0,0 +1,35 @@ +#ifndef AGP_H +#define AGP_H 1 + +#include +#include + +/* + * Functions to keep the agpgart mappings coherent. + * The GART gives the CPU a physical alias of memory. The alias is + * mapped uncacheable. Make sure there are no conflicting mappings + * with different cachability attributes for the same page. + */ + +int map_page_into_agp(struct page *page); +int unmap_page_from_agp(struct page *page); +#define flush_agp_mappings() global_flush_tlb() + +/* Could use CLFLUSH here if the cpu supports it. But then it would + need to be called for each cacheline of the whole page so it may not be + worth it. Would need a page for it. */ +#define flush_agp_cache() wbinvd() + +/* Convert a physical address to an address suitable for the GART. */ +#define phys_to_gart(x) phys_to_machine(x) +#define gart_to_phys(x) machine_to_phys(x) + +/* GATT allocation. Returns/accepts GATT kernel virtual address. */ +#define alloc_gatt_pages(order) ({ \ + char *_t; dma_addr_t _d; \ + _t = dma_alloc_coherent(NULL,PAGE_SIZE<<(order),&_d,GFP_KERNEL); \ + _t; }) +#define free_gatt_pages(table, order) \ + dma_free_coherent(NULL,PAGE_SIZE<<(order),(table),virt_to_bus(table)) + +#endif From 8e6abcd6dae8a16bbff1a8e0dedc30efb7faa662 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:24:18 +0000 Subject: [PATCH 091/282] [XEN] Remove use of 'inline' on functions accessed via pointers. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vmx/vmx.c | 7 +++++++ xen/arch/x86/mm/shadow/multi.c | 8 ++++---- xen/include/asm-x86/hvm/vmx/vmx.h | 7 ------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 6a1f70a79d..7d226e6ba1 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -702,6 +702,13 @@ static int vmx_pae_enabled(struct vcpu *v) return (vmx_paging_enabled(v) && (cr4 & X86_CR4_PAE)); } +/* Works only for vcpu == current */ +static void vmx_update_host_cr3(struct vcpu *v) +{ + ASSERT(v == current); + __vmwrite(HOST_CR3, v->arch.cr3); +} + static void vmx_inject_exception(unsigned int trapnr, int errcode) { vmx_inject_hw_exception(current, trapnr, errcode); diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index efb1f0933d..5dd6a84dd3 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -581,7 +581,7 @@ guest_index(void *ptr) return (u32)((unsigned long)ptr & ~PAGE_MASK) / sizeof(guest_l1e_t); } -static inline u32 +static u32 shadow_l1_index(mfn_t *smfn, u32 guest_index) { #if (GUEST_PAGING_LEVELS == 2) && (SHADOW_PAGING_LEVELS != 2) @@ -593,7 +593,7 @@ shadow_l1_index(mfn_t *smfn, u32 guest_index) #endif } -static inline u32 +static u32 shadow_l2_index(mfn_t *smfn, u32 guest_index) { #if (GUEST_PAGING_LEVELS == 2) && (SHADOW_PAGING_LEVELS != 2) @@ -613,13 +613,13 @@ shadow_l2_index(mfn_t *smfn, u32 guest_index) #if GUEST_PAGING_LEVELS >= 4 -static inline u32 +static u32 shadow_l3_index(mfn_t *smfn, u32 guest_index) { return guest_index; } -static inline u32 +static u32 shadow_l4_index(mfn_t *smfn, u32 guest_index) { return guest_index; diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index e0ec14518b..701edf0e63 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -272,13 +272,6 @@ static inline int vmx_lme_is_set(struct vcpu *v) return efer & EFER_LME; } -/* Works only for vcpu == current */ -static inline void vmx_update_host_cr3(struct vcpu *v) -{ - ASSERT(v == current); - __vmwrite(HOST_CR3, v->arch.cr3); -} - static inline int vmx_pgbit_test(struct vcpu *v) { unsigned long cr0 = v->arch.hvm_vmx.cpu_shadow_cr0; From 90f0b6ab3ad52b4ea2365da19dc5bb78c6fca286 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:27:00 +0000 Subject: [PATCH 092/282] [LINUX] Missing xenoprof.h header file for x86/64. Signed-off-by: Isaku Yamahata --- linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/xenoprof.h | 1 + 1 file changed, 1 insertion(+) create mode 100644 linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/xenoprof.h diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/xenoprof.h b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/xenoprof.h new file mode 100644 index 0000000000..47b3650a06 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/asm/xenoprof.h @@ -0,0 +1 @@ +#include From c669da88e2ae9f0adfab5fc750c966f62577098a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:32:16 +0000 Subject: [PATCH 093/282] [QEMU] Simpler workaround for guest writes to PCI config space that extend past byte 0xff. Signed-off-by: Keir Fraser --- tools/ioemu/hw/pci.c | 24 ++++++++---------------- tools/ioemu/vl.h | 7 +++++-- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/tools/ioemu/hw/pci.c b/tools/ioemu/hw/pci.c index cea81f7b7f..77737c8615 100644 --- a/tools/ioemu/hw/pci.c +++ b/tools/ioemu/hw/pci.c @@ -221,24 +221,17 @@ uint32_t pci_default_read_config(PCIDevice *d, uint32_t address, int len) { uint32_t val; - switch(len) { - default: - case 4: - if (address <= 0xfc) { - val = le32_to_cpu(*(uint32_t *)(d->config + address)); - break; - } - /* fall through */ - case 2: - if (address <= 0xfe) { - val = le16_to_cpu(*(uint16_t *)(d->config + address)); - break; - } - /* fall through */ case 1: val = d->config[address]; break; + case 2: + val = le16_to_cpu(*(uint16_t *)(d->config + address)); + break; + default: + case 4: + val = le32_to_cpu(*(uint32_t *)(d->config + address)); + break; } return val; } @@ -340,8 +333,7 @@ void pci_default_write_config(PCIDevice *d, d->config[addr] = val; } - if (++addr > 0xff) - break; + addr++; val >>= 8; } diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 4ff660c217..3df963241c 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -650,8 +650,11 @@ typedef struct PCIIORegion { #define PCI_MAX_LAT 0x3f /* 8 bits */ struct PCIDevice { - /* PCI config space */ - uint8_t config[256]; + /* + * PCI config space. The 4 extra bytes are a safety buffer for guest + * word/dword writes that can extend past byte 0xff. + */ + uint8_t config[256+4]; /* the following fields are read only */ PCIBus *bus; From 671ac0de22689db93afb37dce54837641f353f46 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:33:11 +0000 Subject: [PATCH 094/282] [QEMU] usb-uhci: Data buffer is too small The data buffer is only 1280 bytes long but the user-supplied length can be as large as 0x7ff. This patch extends the buffer to 2048 bytes. Signed-off-by: Herbert Xu --- tools/ioemu/hw/usb-uhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ioemu/hw/usb-uhci.c b/tools/ioemu/hw/usb-uhci.c index c6394cdda3..4b8db28717 100644 --- a/tools/ioemu/hw/usb-uhci.c +++ b/tools/ioemu/hw/usb-uhci.c @@ -421,7 +421,7 @@ static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) { uint8_t pid; - uint8_t buf[1280]; + uint8_t buf[2048]; int len, max_len, err, ret; if (td->ctrl & TD_CTRL_IOC) { From f6656783078c6a4d0c2397a24acd3774403ab42f Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:34:48 +0000 Subject: [PATCH 095/282] [LINUX] Properly trigger XenbusStateClosed in blkfront In some situations, like when error happens in block attach for a guest in dom0, backend send us XenbusStateClosing notification. However, as frontend were never properly initialized, it fails to change its own state to XenbusStateClosed, leaving the system in a dead-end state. Signed-off-by: Glauber de Oliveira Costa --- linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c index 95cff46ff9..6b7100a1bc 100644 --- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c +++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c @@ -359,7 +359,7 @@ static void blkfront_closing(struct xenbus_device *dev) DPRINTK("blkfront_closing: %s removed\n", dev->nodename); if (info->rq == NULL) - return; + goto out; spin_lock_irqsave(&blkif_io_lock, flags); /* No more blkif_request(). */ @@ -373,6 +373,7 @@ static void blkfront_closing(struct xenbus_device *dev) xlvbd_del(info); + out: xenbus_frontend_closed(dev); } From 9cac7135b1f90cedd8328f2741cc515714bb7e5a Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:36:03 +0000 Subject: [PATCH 096/282] [LIBXC] Fix Solaris build: Use XC_PAGE_SIZE not PAGE_SIZE. Signed-off-by: John Levon --- tools/python/xen/lowlevel/xc/xc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 2df6beaa54..2eb9376426 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -392,7 +392,7 @@ static PyObject *pyxc_hvm_build(XcObject *self, return PyErr_SetFromErrno(xc_error); /* Set up the HVM info table. */ - va_map = xc_map_foreign_range(self->xc_handle, dom, PAGE_SIZE, + va_map = xc_map_foreign_range(self->xc_handle, dom, XC_PAGE_SIZE, PROT_READ | PROT_WRITE, HVM_INFO_PFN); if ( va_map == NULL ) @@ -407,7 +407,7 @@ static PyObject *pyxc_hvm_build(XcObject *self, for ( i = 0, sum = 0; i < va_hvm->length; i++ ) sum += ((uint8_t *)va_hvm)[i]; va_hvm->checksum = -sum; - munmap(va_map, PAGE_SIZE); + munmap(va_map, XC_PAGE_SIZE); xc_get_hvm_param(self->xc_handle, dom, HVM_PARAM_STORE_PFN, &store_mfn); xc_set_hvm_param(self->xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae); From 2a7916e953aa1231b709510d0bf081119cf097c0 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 30 Nov 2006 17:47:50 +0000 Subject: [PATCH 097/282] [QEMU] Do shift-key processing in QEMU monitor terminal when connected via VNC. Signed-off-by: Daniel P. Berrange --- tools/ioemu/vnc.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c index 631754ca03..86d3720f90 100644 --- a/tools/ioemu/vnc.c +++ b/tools/ioemu/vnc.c @@ -114,6 +114,7 @@ struct VncState int visible_h; int ctl_keys; /* Ctrl+Alt starts calibration */ + int shift_keys; /* Shift / CapsLock keys */ }; #define DIRTY_PIXEL_BITS 64 @@ -870,9 +871,12 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) } else if (down) { int qemu_keysym = 0; - if (sym <= 128) /* normal ascii */ + if (sym <= 128) { /* normal ascii */ + int shifted = vs->shift_keys == 1 || vs->shift_keys == 2; qemu_keysym = sym; - else { + if (sym >= 'a' && sym <= 'z' && shifted) + qemu_keysym -= 'a' - 'A'; + } else { switch (sym) { case XK_Up: qemu_keysym = QEMU_KEY_UP; break; case XK_Down: qemu_keysym = QEMU_KEY_DOWN; break; @@ -903,6 +907,10 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) vs->ctl_keys |= 2; break; + case XK_Shift_L: + vs->shift_keys |= 1; + break; + default: break; } @@ -916,6 +924,14 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) vs->ctl_keys &= ~2; break; + case XK_Shift_L: + vs->shift_keys &= ~1; + break; + + case XK_Caps_Lock: + vs->shift_keys ^= 2; + break; + case XK_1 ... XK_9: if ((vs->ctl_keys & 3) != 3) break; From 55b918302fabef639c2bf7fac5256eda92a39270 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 17:53:59 +0000 Subject: [PATCH 098/282] [LINUX] Only initialise kexec in domain0. Signed-off-by: Ian Campbell --- linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c index 08820ad37d..d4c248eccd 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -22,6 +22,9 @@ void xen_machine_kexec_setup_resources(void) struct resource *res; int k = 0; + if (!is_initial_xendomain()) + return; + /* determine maximum number of physical cpus */ while (1) { From ac5ea23a6db5931a0a6c99734e79fae82bff3908 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 30 Nov 2006 17:28:51 +0000 Subject: [PATCH 099/282] Reinstate the reboot-feature code that was accidentally lost as part of the merge in changeset 12189. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/image.py | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 98397d76ca..afff1b084e 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -280,6 +280,7 @@ class HVMImageHandler(ImageHandler): log.debug("apic = %d", self.apic) self.register_shutdown_watch() + self.register_reboot_feature_watch() return xc.hvm_build(domid = self.vm.getDomid(), image = self.kernel, @@ -420,6 +421,7 @@ class HVMImageHandler(ImageHandler): def destroy(self): self.unregister_shutdown_watch() + self.unregister_reboot_feature_watch(); if not self.pid: return try: @@ -470,6 +472,39 @@ class HVMImageHandler(ImageHandler): return 1 # Keep watching + def register_reboot_feature_watch(self): + """ add xen store watch on control/feature-reboot """ + self.rebootFeatureWatch = xswatch(self.vm.dompath + "/control/feature-reboot", \ + self.hvm_reboot_feature) + log.debug("hvm reboot feature watch registered") + + def unregister_reboot_feature_watch(self): + """Remove the watch on the control/feature-reboot, if any. Nothrow + guarantee.""" + + try: + if self.rebootFeatureWatch: + self.rebootFeatureWatch.unwatch() + except: + log.exception("Unwatching hvm reboot feature watch failed.") + self.rebootFeatureWatch = None + log.debug("hvm reboot feature watch unregistered") + + def hvm_reboot_feature(self, _): + """ watch call back on node control/feature-reboot, + if node changed, this function will be called + """ + xd = xen.xend.XendDomain.instance() + vm = xd.domain_lookup( self.vm.getDomid() ) + + status = vm.readDom('control/feature-reboot') + log.debug("hvm_reboot_feature fired, module status=%s", status) + if status == '1': + self.unregister_shutdown_watch() + + return 1 # Keep watching + + class IA64_HVM_ImageHandler(HVMImageHandler): ostype = "hvm" From 9523b514697fe78558f4a840f91e6a497936629f Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 30 Nov 2006 18:05:19 +0000 Subject: [PATCH 100/282] Fix-up reference to name_label. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomain.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index b21f762d13..cc19c469e1 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -184,15 +184,13 @@ class XendDomain: if not dom_uuid: continue - dom_name = dom.get('name', 'Domain-%s' % dom_uuid) + dom_name = dom.get('name_label', 'Domain-%s' % dom_uuid) try: running_dom = self.domain_lookup_nr(dom_name) if not running_dom: # instantiate domain if not started. new_dom = XendDomainInfo.createDormant(dom) self._managed_domain_register(new_dom) - else: - self._managed_domain_register(running_dom) except Exception: log.exception("Failed to create reference to managed " "domain: %s" % dom_name) From 69f4bf70a085c6e395a73e71c0e70cec43d7a1a6 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 30 Nov 2006 18:08:34 +0000 Subject: [PATCH 101/282] Fix HVM shutdown when xend is restarted. Added a recreate call to ImageHandler, allowing the subclasses of that to hook into the code that runs when xend restarts. This allows us in particular to reregister the watches for HVM shutdown, and read the PID of qemu-dm from the store. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendConstants.py | 2 + tools/python/xen/xend/XendDomain.py | 1 - tools/python/xen/xend/XendDomainInfo.py | 40 ++++++++++------ tools/python/xen/xend/image.py | 64 ++++++++++++++----------- 4 files changed, 65 insertions(+), 42 deletions(-) diff --git a/tools/python/xen/xend/XendConstants.py b/tools/python/xen/xend/XendConstants.py index 96f7a22d7e..e07fa127f1 100644 --- a/tools/python/xen/xend/XendConstants.py +++ b/tools/python/xen/xend/XendConstants.py @@ -34,6 +34,8 @@ DOMAIN_SHUTDOWN_REASONS = { DOMAIN_CRASH : "crash", DOMAIN_HALT : "halt" } +REVERSE_DOMAIN_SHUTDOWN_REASONS = \ + dict([(y, x) for x, y in DOMAIN_SHUTDOWN_REASONS.items()]) restart_modes = [ "restart", diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index cc19c469e1..ed3df761df 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -421,7 +421,6 @@ class XendDomain: self._remove_domain(dom, domid) - def _add_domain(self, info): """Add a domain to the list of running domains diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 61f7c49192..91aef24838 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -226,6 +226,15 @@ def recreate(info, priv): vm._storeVmDetails() vm._storeDomDetails() + if vm.info['image']: # Only dom0 should be without an image entry when + # recreating, but we cope with missing ones + # elsewhere just in case. + vm.image = image.create(vm, + vm.info, + vm.info['image'], + vm.info['devices']) + vm.image.recreate() + vm._registerWatches() vm.refreshShutdown(xeninfo) return vm @@ -470,7 +479,7 @@ class XendDomainInfo: if reason not in DOMAIN_SHUTDOWN_REASONS.values(): raise XendError('Invalid reason: %s' % reason) - self._storeDom("control/shutdown", reason) + self.storeDom("control/shutdown", reason) def pause(self): """Pause domain @@ -497,7 +506,7 @@ class XendDomainInfo: def send_sysrq(self, key): """ Send a Sysrq equivalent key via xenstored.""" asserts.isCharConvertible(key) - self._storeDom("control/sysrq", '%c' % key) + self.storeDom("control/sysrq", '%c' % key) def device_create(self, dev_config): """Create a new device. @@ -581,7 +590,7 @@ class XendDomainInfo: self.info['memory_static_min'] = target self.storeVm("memory", target) - self._storeDom("memory/target", target << 10) + self.storeDom("memory/target", target << 10) def getVCPUInfo(self): try: @@ -648,7 +657,7 @@ class XendDomainInfo: for devclass in XendDevices.valid_devices(): devconfig = self.getDeviceController(devclass).configurations() if devconfig: - devices.extend(map(lambda conf: (devclass, conf), devconfig)) + devices.extend(devconfig) if not self.info['devices'] and devices is not None: for device in devices: @@ -677,16 +686,19 @@ class XendDomainInfo: # Function to update xenstore /dom/* # - def _readDom(self, *args): + def readDom(self, *args): return xstransact.Read(self.dompath, *args) + def gatherDom(self, *args): + return xstransact.Gather(self.dompath, *args) + def _writeDom(self, *args): return xstransact.Write(self.dompath, *args) def _removeDom(self, *args): return xstransact.Remove(self.dompath, *args) - def _storeDom(self, *args): + def storeDom(self, *args): return xstransact.Store(self.dompath, *args) def _recreateDom(self): @@ -787,17 +799,17 @@ class XendDomainInfo: def _handleShutdownWatch(self, _): log.debug('XendDomainInfo.handleShutdownWatch') - reason = self._readDom('control/shutdown') + reason = self.readDom('control/shutdown') if reason and reason != 'suspend': - sst = self._readDom('xend/shutdown_start_time') + sst = self.readDom('xend/shutdown_start_time') now = time.time() if sst: self.shutdownStartTime = float(sst) timeout = float(sst) + SHUTDOWN_TIMEOUT - now else: self.shutdownStartTime = now - self._storeDom('xend/shutdown_start_time', now) + self.storeDom('xend/shutdown_start_time', now) timeout = SHUTDOWN_TIMEOUT log.trace( @@ -828,7 +840,7 @@ class XendDomainInfo: return self.dompath def getShutdownReason(self): - return self._readDom('control/shutdown') + return self.readDom('control/shutdown') def getStorePort(self): """For use only by image.py and XendCheckpoint.py.""" @@ -914,7 +926,7 @@ class XendDomainInfo: return elif xeninfo['crashed']: - if self._readDom('xend/shutdown_completed'): + if self.readDom('xend/shutdown_completed'): # We've seen this shutdown already, but we are preserving # the domain for debugging. Leave it alone. return @@ -930,7 +942,7 @@ class XendDomainInfo: elif xeninfo['shutdown']: self._stateSet(DOM_STATE_SHUTDOWN) - if self._readDom('xend/shutdown_completed'): + if self.readDom('xend/shutdown_completed'): # We've seen this shutdown already, but we are preserving # the domain for debugging. Leave it alone. return @@ -1111,7 +1123,7 @@ class XendDomainInfo: log.info("Preserving dead domain %s (%d).", self.info['name_label'], self.domid) self._unwatchVm() - self._storeDom('xend/shutdown_completed', 'True') + self.storeDom('xend/shutdown_completed', 'True') self._stateSet(DOM_STATE_HALTED) # @@ -1724,7 +1736,7 @@ class XendDomainInfo: ignore_devices = ignore_store) if not ignore_store and self.dompath: - vnc_port = self._readDom('console/vnc-port') + vnc_port = self.readDom('console/vnc-port') if vnc_port is not None: result.append(['device', ['console', ['vnc-port', str(vnc_port)]]]) diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index afff1b084e..31194c7a73 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -23,6 +23,7 @@ import math import signal import xen.lowlevel.xc +from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS from xen.xend.XendError import VmError, XendError from xen.xend.XendLogging import log from xen.xend.server.netif import randomMAC @@ -165,6 +166,10 @@ class ImageHandler: pass + def recreate(self): + pass + + class LinuxImageHandler(ImageHandler): ostype = "linux" @@ -232,9 +237,12 @@ class PPC_LinuxImageHandler(LinuxImageHandler): class HVMImageHandler(ImageHandler): + ostype = "hvm" + def __init__(self, vm, vmConfig, imageConfig, deviceConfig): ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig) self.shutdownWatch = None + self.rebootFeatureWatch = None def configure(self, vmConfig, imageConfig, deviceConfig): ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig) @@ -257,7 +265,7 @@ class HVMImageHandler(ImageHandler): ("image/device-model", self.device_model), ("image/display", self.display)) - self.pid = 0 + self.pid = None self.dmargs += self.configVNC(imageConfig) @@ -417,20 +425,30 @@ class HVMImageHandler(ImageHandler): log.info("spawning device models: %s %s", self.device_model, args) # keep track of pid and spawned options to kill it later self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env) + self.vm.storeDom("image/device-model-pid", self.pid) log.info("device model pid: %d", self.pid) + def recreate(self): + self.register_shutdown_watch() + self.register_reboot_feature_watch() + self.pid = self.vm.gatherDom(('image/device-model-pid', int)) + def destroy(self): self.unregister_shutdown_watch() self.unregister_reboot_feature_watch(); - if not self.pid: - return - try: - os.kill(self.pid, signal.SIGKILL) - os.waitpid(self.pid, 0) - except OSError, e: - log.warning("Unable to kill device model (pid: %d)" % self.pid) - - self.pid = 0 + if self.pid: + try: + os.kill(self.pid, signal.SIGKILL) + except OSError, exn: + log.exception(exn) + try: + os.waitpid(self.pid, 0) + except OSError, exn: + # This is expected if Xend has been restarted within the + # life of this domain. In this case, we can kill the process, + # but we can't wait for it because it's not our child. + pass + self.pid = None def register_shutdown_watch(self): """ add xen store watch on control/shutdown """ @@ -454,23 +472,22 @@ class HVMImageHandler(ImageHandler): """ watch call back on node control/shutdown, if node changed, this function will be called """ - from xen.xend.XendConstants import DOMAIN_SHUTDOWN_REASONS xd = xen.xend.XendDomain.instance() try: vm = xd.domain_lookup( self.vm.getDomid() ) except XendError: # domain isn't registered, no need to clean it up. - return + return False reason = vm.getShutdownReason() log.debug("hvm_shutdown fired, shutdown reason=%s", reason) - for x in DOMAIN_SHUTDOWN_REASONS.keys(): - if DOMAIN_SHUTDOWN_REASONS[x] == reason: - vm.info['shutdown'] = 1 - vm.info['shutdown_reason'] = x - vm.refreshShutdown(vm.info) + if reason in REVERSE_DOMAIN_SHUTDOWN_REASONS: + vm.info['shutdown'] = 1 + vm.info['shutdown_reason'] = \ + REVERSE_DOMAIN_SHUTDOWN_REASONS[reason] + vm.refreshShutdown(vm.info) - return 1 # Keep watching + return True # Keep watching def register_reboot_feature_watch(self): """ add xen store watch on control/feature-reboot """ @@ -494,21 +511,16 @@ class HVMImageHandler(ImageHandler): """ watch call back on node control/feature-reboot, if node changed, this function will be called """ - xd = xen.xend.XendDomain.instance() - vm = xd.domain_lookup( self.vm.getDomid() ) - - status = vm.readDom('control/feature-reboot') + status = self.vm.readDom('control/feature-reboot') log.debug("hvm_reboot_feature fired, module status=%s", status) if status == '1': self.unregister_shutdown_watch() - return 1 # Keep watching + return True # Keep watching class IA64_HVM_ImageHandler(HVMImageHandler): - ostype = "hvm" - def getRequiredAvailableMemory(self, mem_kb): page_kb = 16 # ROM size for guest firmware, ioreq page and xenstore page @@ -521,8 +533,6 @@ class IA64_HVM_ImageHandler(HVMImageHandler): class X86_HVM_ImageHandler(HVMImageHandler): - ostype = "hvm" - def getRequiredAvailableMemory(self, mem_kb): # Add 8 MiB overhead for QEMU's video RAM. return mem_kb + 8192 From fcd9174e64b1f0f5f084c3d7f3c2c59c0dbf34ee Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 18:21:50 +0000 Subject: [PATCH 102/282] [LINUX] Fix backward compatibility with hypervisors which do not support kexec. Also do not rely on side effects in BUG_ON(x) -- use if(x) BUG() instead. Signed-off-by: Ian Campbell --- .../drivers/xen/core/machine_kexec.c | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c index d4c248eccd..88a2423340 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -20,7 +20,7 @@ void xen_machine_kexec_setup_resources(void) { xen_kexec_range_t range; struct resource *res; - int k = 0; + int err, k = 0; if (!is_initial_xendomain()) return; @@ -32,8 +32,16 @@ void xen_machine_kexec_setup_resources(void) range.range = KEXEC_RANGE_MA_CPU; range.nr = k; - if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) + /* + * Anything other than EINVAL or success indictates + * that we are not running on a hypervisor which + * supports kexec. + */ + err = HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range); + if (err == -EINVAL) break; + else if (err) + return; k++; } @@ -52,7 +60,8 @@ void xen_machine_kexec_setup_resources(void) range.range = KEXEC_RANGE_MA_CPU; range.nr = k; - BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)); + if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) + BUG(); res = xen_phys_cpus + k; @@ -68,7 +77,8 @@ void xen_machine_kexec_setup_resources(void) memset(&range, 0, sizeof(range)); range.range = KEXEC_RANGE_MA_XEN; - BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)); + if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) + BUG(); xen_hypervisor_res.name = "Hypervisor code and data"; xen_hypervisor_res.start = range.start; @@ -80,7 +90,8 @@ void xen_machine_kexec_setup_resources(void) memset(&range, 0, sizeof(range)); range.range = KEXEC_RANGE_MA_CRASH; - BUG_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)); + if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) + BUG(); if (range.size) { crashk_res.start = range.start; From 5419258cad363451db58081c11a10b472a4be417 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 18:44:54 +0000 Subject: [PATCH 103/282] [XEN] Rename machine_shutdown to machine_reboot_kexec to better reflect its purpose. Signed-off-by: Ian Campbell --- xen/arch/ia64/xen/machine_kexec.c | 2 +- xen/arch/powerpc/machine_kexec.c | 2 +- xen/arch/x86/machine_kexec.c | 8 ++++---- xen/common/kexec.c | 2 +- xen/include/xen/kexec.h | 4 +++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/xen/arch/ia64/xen/machine_kexec.c b/xen/arch/ia64/xen/machine_kexec.c index 639f845ac1..df7ad0c9b6 100644 --- a/xen/arch/ia64/xen/machine_kexec.c +++ b/xen/arch/ia64/xen/machine_kexec.c @@ -18,7 +18,7 @@ void machine_kexec(xen_kexec_image_t *image) printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } -void machine_shutdown(xen_kexec_image_t *image) +void machine_reboot_kexec(xen_kexec_image_t *image) { printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } diff --git a/xen/arch/powerpc/machine_kexec.c b/xen/arch/powerpc/machine_kexec.c index 639f845ac1..df7ad0c9b6 100644 --- a/xen/arch/powerpc/machine_kexec.c +++ b/xen/arch/powerpc/machine_kexec.c @@ -18,7 +18,7 @@ void machine_kexec(xen_kexec_image_t *image) printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } -void machine_shutdown(xen_kexec_image_t *image) +void machine_reboot_kexec(xen_kexec_image_t *image) { printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); } diff --git a/xen/arch/x86/machine_kexec.c b/xen/arch/x86/machine_kexec.c index 64a4a3f19f..81c392a7d3 100644 --- a/xen/arch/x86/machine_kexec.c +++ b/xen/arch/x86/machine_kexec.c @@ -52,7 +52,7 @@ void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) { } -static void __machine_shutdown(void *data) +static void __machine_reboot_kexec(void *data) { xen_kexec_image_t *image = (xen_kexec_image_t *)data; @@ -69,7 +69,7 @@ static void __machine_shutdown(void *data) machine_kexec(image); } -void machine_shutdown(xen_kexec_image_t *image) +void machine_reboot_kexec(xen_kexec_image_t *image) { int reboot_cpu_id; cpumask_t reboot_cpu; @@ -83,13 +83,13 @@ void machine_shutdown(xen_kexec_image_t *image) { cpus_clear(reboot_cpu); cpu_set(reboot_cpu_id, reboot_cpu); - on_selected_cpus(reboot_cpu, __machine_shutdown, image, 1, 0); + on_selected_cpus(reboot_cpu, __machine_reboot_kexec, image, 1, 0); for (;;) ; /* nothing */ } else { - __machine_shutdown(image); + __machine_reboot_kexec(image); } BUG(); } diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 2c4c079314..31e581a07f 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -306,7 +306,7 @@ static int kexec_exec(XEN_GUEST_HANDLE(void) uarg) case KEXEC_TYPE_DEFAULT: image = &kexec_image[base + pos]; one_cpu_only(); - machine_shutdown(image); /* Does not return */ + machine_reboot_kexec(image); /* Does not return */ break; case KEXEC_TYPE_CRASH: machine_crash_kexec(); /* Does not return */ diff --git a/xen/include/xen/kexec.h b/xen/include/xen/kexec.h index cebc2d793a..c22bfc8f5e 100644 --- a/xen/include/xen/kexec.h +++ b/xen/include/xen/kexec.h @@ -12,6 +12,8 @@ typedef struct xen_kexec_reserve { unsigned long start; } xen_kexec_reserve_t; +extern xen_kexec_reserve_t kexec_crash_area; + /* We have space for 4 images to support atomic update * of images. This is important for CRASH images since * a panic can happen at any time... @@ -24,7 +26,7 @@ typedef struct xen_kexec_reserve { int machine_kexec_load(int type, int slot, xen_kexec_image_t *image); void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image); void machine_kexec_reserved(xen_kexec_reserve_t *reservation); -void machine_shutdown(xen_kexec_image_t *image); +void machine_reboot_kexec(xen_kexec_image_t *image); void machine_crash_kexec(void); void machine_crash_save_cpu(void); crash_xen_info_t *machine_crash_save_info(void); From a0d286b852b5bf0c02eebad6a1ba441b7e4c58b8 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 30 Nov 2006 18:44:55 +0000 Subject: [PATCH 104/282] [XEN] Only parse the crashkernel command line parameter once on boot not each time it is requested. Signed-off-by: Ian Campbell --- xen/arch/x86/setup.c | 8 +++---- xen/common/kexec.c | 51 +++++++++++++++++++------------------------- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 43d1f63b71..391a50eb05 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -299,7 +299,6 @@ void __init __start_xen(multiboot_info_t *mbi) unsigned long nr_pages, modules_length; paddr_t s, e; int i, e820_warn = 0, e820_raw_nr = 0, bytes = 0; - xen_kexec_reserve_t crash_area; struct ns16550_defaults ns16550 = { .data_bits = 8, .parity = 'n', @@ -480,8 +479,7 @@ void __init __start_xen(multiboot_info_t *mbi) #endif } - machine_kexec_reserved(&crash_area); - if ( crash_area.size > 0 ) + if ( kexec_crash_area.size > 0 ) { unsigned long kdump_start, kdump_size, k; @@ -489,8 +487,8 @@ void __init __start_xen(multiboot_info_t *mbi) init_boot_pages(initial_images_start, initial_images_end); - kdump_start = crash_area.start; - kdump_size = crash_area.size; + kdump_start = kexec_crash_area.start; + kdump_size = kexec_crash_area.size; printk("Kdump: %luMB (%lukB) at 0x%lx\n", kdump_size >> 20, diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 31e581a07f..f3f5f01731 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -22,9 +22,6 @@ #include #include -static char opt_crashkernel[32] = ""; -string_param("crashkernel", opt_crashkernel); - DEFINE_PER_CPU (crash_note_t, crash_notes); cpumask_t crash_saved_cpus; int crashing_cpu; @@ -39,6 +36,26 @@ unsigned long kexec_flags = 0; /* the lowest bits are for KEXEC_IMAGE... */ spinlock_t kexec_lock = SPIN_LOCK_UNLOCKED; +xen_kexec_reserve_t kexec_crash_area; + +static void __init parse_crashkernel(char *str) +{ + unsigned long start, size; + + size = parse_size_and_unit(str, &str); + if ( *str == '@' ) + start = parse_size_and_unit(str+1, NULL); + else + start = 0; + + if ( start && size ) + { + kexec_crash_area.start = start; + kexec_crash_area.size = size; + } +} +custom_param("crashkernel", parse_crashkernel); + static void one_cpu_only(void) { /* Only allow the first cpu to continue - force other cpus to spin */ @@ -134,34 +151,10 @@ static __init int register_crashdump_trigger(void) } __initcall(register_crashdump_trigger); -void machine_kexec_reserved(xen_kexec_reserve_t *reservation) -{ - unsigned long start, size; - char *str = opt_crashkernel; - - memset(reservation, 0, sizeof(*reservation)); - - size = parse_size_and_unit(str, &str); - if ( *str == '@' ) - start = parse_size_and_unit(str+1, NULL); - else - start = 0; - - if ( start && size ) - { - reservation->start = start; - reservation->size = size; - } -} - static int kexec_get_reserve(xen_kexec_range_t *range) { - xen_kexec_reserve_t reservation; - - machine_kexec_reserved(&reservation); - - range->start = reservation.start; - range->size = reservation.size; + range->start = kexec_crash_area.start; + range->size = kexec_crash_area.size; return 0; } From be61b6ee0598879f34f4ddfcc96d13e4ad894d70 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 30 Nov 2006 19:11:51 +0000 Subject: [PATCH 105/282] Fix registration on managed domains on xend restart. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomain.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index ed3df761df..9a4d112e95 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -191,6 +191,8 @@ class XendDomain: # instantiate domain if not started. new_dom = XendDomainInfo.createDormant(dom) self._managed_domain_register(new_dom) + else: + self._managed_domain_register(running_dom) except Exception: log.exception("Failed to create reference to managed " "domain: %s" % dom_name) From f99727ee65ec571f94f3de8f011858fcb931c41b Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 30 Nov 2006 20:07:58 +0000 Subject: [PATCH 106/282] Fix managed domain rebooting by only complaining about a VM name conflict if the VM UUID conflicts as well. Also, remove the previous_restart_time node when explicitly rebooting a guest -- the user ought to be able to drive reboots faster than the safety catch. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 91aef24838..d606dbb7bb 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -479,8 +479,9 @@ class XendDomainInfo: if reason not in DOMAIN_SHUTDOWN_REASONS.values(): raise XendError('Invalid reason: %s' % reason) + self._removeVm('xend/previous_restart_time') self.storeDom("control/shutdown", reason) - + def pause(self): """Pause domain @@ -1692,8 +1693,9 @@ class XendDomainInfo: raise VmError('Invalid VM Name') dom = XendDomain.instance().domain_lookup_nr(name) - if dom and dom != self and not dom.info['dying']: - raise VmError("VM name '%s' already exists" % name) + if dom and dom.info['uuid'] != self.info['uuid']: + raise VmError("VM name '%s' already exists as domain %s" % + (name, str(dom.domid))) def update(self, info = None, refresh = True): From 6a7c1b4ee045e5ab2bfa0d32fa22a5b98e20696d Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 30 Nov 2006 20:16:54 +0000 Subject: [PATCH 107/282] Fix default for the authentication on the Xen-API server -- the default should be PAM, not none! Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvServer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 934e6d300b..f995a13bf9 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -154,7 +154,7 @@ def create(): if api_cfg: try: addrs = [(str(x[0]).split(':'), - len(x) > 1 and x[1] or XendAPI.AUTH_NONE, + len(x) > 1 and x[1] or XendAPI.AUTH_PAM, len(x) > 2 and x[2] and map(re.compile, x[2].split(" ")) or None) for x in api_cfg] From 96403247eb6b2c8da2592f370f53a29bb892e428 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:15 -0700 Subject: [PATCH 108/282] [IA64] Fix sparse tree xenoprof/perfmon/oprofile build dependencies Compile xenoprof perfmon related hypercall even when CONFIG_PERFMON, CONFIG_OPROFILE, CONFIG_OPROFILE_MODULE are disabled. They should be compiled in vmlinux unconditionally because they might be called by other modules in theory. Signed-off-by: Isaku Yamahata --- linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c | 4 ---- linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c | 4 ---- linux-2.6-xen-sparse/include/asm-ia64/hypercall.h | 2 -- linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h | 8 -------- 4 files changed, 18 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c index ec46b84037..49f9ea6708 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c @@ -304,7 +304,6 @@ xencomm_hypercall_suspend(unsigned long srec) return xencomm_arch_hypercall_suspend(xencomm_create_inline(&arg)); } -#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) int xencomm_hypercall_xenoprof_op(int op, void *arg) { @@ -336,9 +335,7 @@ xencomm_hypercall_xenoprof_op(int op, void *arg) return xencomm_arch_hypercall_xenoprof_op(op, xencomm_create_inline(arg)); } -#endif -#ifdef CONFIG_PERFMON int xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count) { @@ -366,4 +363,3 @@ xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count) xencomm_create_inline(arg), count); } -#endif diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c index adc01f1fd5..a2f2c97ac4 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c @@ -323,7 +323,6 @@ xencomm_mini_hypercall_xen_version(int cmd, void *arg) } EXPORT_SYMBOL(xencomm_mini_hypercall_xen_version); -#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) int xencomm_mini_hypercall_xenoprof_op(int op, void *arg) { @@ -372,9 +371,7 @@ xencomm_mini_hypercall_xenoprof_op(int op, void *arg) return xencomm_arch_hypercall_xenoprof_op(op, desc); } EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_xenoprof_op); -#endif -#ifdef CONFIG_PERFMON int xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count) @@ -418,4 +415,3 @@ xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, return xencomm_arch_hypercall_perfmon_op(cmd, desc, count); } EXPORT_SYMBOL_GPL(xencomm_mini_hypercall_perfmon_op); -#endif diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h index 67b8526f69..4b5ea2dae0 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h @@ -399,7 +399,6 @@ HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, } #endif -#ifdef CONFIG_PERFMON static inline int xencomm_arch_hypercall_perfmon_op(unsigned long cmd, struct xencomm_handle *arg, @@ -408,7 +407,6 @@ xencomm_arch_hypercall_perfmon_op(unsigned long cmd, return _hypercall4(int, ia64_dom0vp_op, IA64_DOM0VP_perfmon, cmd, arg, count); } -#endif // for balloon driver #define HYPERVISOR_update_va_mapping(va, new_val, flags) (0) diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h index df5204f469..79e790d75b 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h @@ -46,14 +46,10 @@ extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg); extern int xencomm_hypercall_suspend(unsigned long srec); -#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) extern int xencomm_hypercall_xenoprof_op(int op, void *arg); -#endif -#ifdef CONFIG_PERFMON extern int xencomm_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count); -#endif /* Using mini xencomm. */ extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str); @@ -77,14 +73,10 @@ extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg); extern unsigned long xencomm_mini_hypercall_hvm_op(int cmd, void *arg); -#if defined(CONFIG_OPROFILE) || defined(CONFIG_OPROFILE_MODULE) extern int xencomm_mini_hypercall_xenoprof_op(int op, void *arg); -#endif -#ifdef CONFIG_PERFMON extern int xencomm_mini_hypercall_perfmon_op(unsigned long cmd, void* arg, unsigned long count); -#endif /* For privcmd. Locally declare argument type to avoid include storm. Type coherency will be checked within privcmd.c */ From 316af7fb4eb33c6dd0a2dc05efaf7c7b16098013 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:20 -0700 Subject: [PATCH 109/282] [IA64] Update PV-on-HVM to follow status of interrupt controller Follow-on to xen-unstable cangeset: http://xenbits.xensource.com/xen-unstable.hg?cs=fe5ed694b0c2 - Follow to change a method of interrupt handling in latest changeset. - Modify to change the spec of callback IRQ in hypervisor side. - Modify to follow status of interrupt mask register of virtual interupt controller. - Modify to deliver interupts to a CPU specified with virtual interrupt controller. http://lists.xensource.com/archives/html/xen-ia64-devel/2006-11/msg00159.html Signed-off-by: Tsunehisa Doi Signed-off-by: Kouya SHIMURA --- xen/arch/ia64/vmx/vlsapic.c | 10 ++++++++-- xen/arch/ia64/vmx/vmx_process.c | 12 ++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/xen/arch/ia64/vmx/vlsapic.c b/xen/arch/ia64/vmx/vlsapic.c index d2963fdf91..2fa0245099 100644 --- a/xen/arch/ia64/vmx/vlsapic.c +++ b/xen/arch/ia64/vmx/vlsapic.c @@ -103,8 +103,10 @@ static int vmx_vcpu_unpend_interrupt(VCPU *vcpu, uint8_t vector) ret = test_and_clear_bit(vector, &VCPU(vcpu, irr[0])); local_irq_restore(spsr); - if (ret) + if (ret) { vcpu->arch.irq_new_pending = 1; + wmb(); + } return ret; } @@ -488,8 +490,10 @@ int vmx_vcpu_pend_interrupt(VCPU *vcpu, uint8_t vector) ret = test_and_set_bit(vector, &VCPU(vcpu, irr[0])); local_irq_restore(spsr); - if (!ret) + if (!ret) { vcpu->arch.irq_new_pending = 1; + wmb(); + } return ret; } @@ -511,6 +515,7 @@ void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, u64 *pend_irr) } local_irq_restore(spsr); vcpu->arch.irq_new_pending = 1; + wmb(); } /* @@ -572,6 +577,7 @@ void guest_write_eoi(VCPU *vcpu) VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63)); VCPU(vcpu, eoi)=0; // overwrite the data vcpu->arch.irq_new_pending=1; + wmb(); } int is_unmasked_irq(VCPU *vcpu) diff --git a/xen/arch/ia64/vmx/vmx_process.c b/xen/arch/ia64/vmx/vmx_process.c index 3526175cbd..d6c5c295d1 100644 --- a/xen/arch/ia64/vmx/vmx_process.c +++ b/xen/arch/ia64/vmx/vmx_process.c @@ -225,15 +225,15 @@ void leave_hypervisor_tail(struct pt_regs *regs) if (v->vcpu_id == 0) { int callback_irq = d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; - if (callback_irq != 0 && local_events_need_delivery()) { - /*inject para-device call back irq*/ - v->vcpu_info->evtchn_upcall_mask = 1; - vmx_vcpu_pend_interrupt(v, callback_irq); + if (callback_irq != 0) { + /* change level for para-device callback irq */ + vmx_vioapic_set_irq(d, callback_irq, + local_events_need_delivery()); } } - if ( v->arch.irq_new_pending ) { - v->arch.irq_new_pending = 0; + rmb(); + if (xchg(&v->arch.irq_new_pending, 0)) { v->arch.irq_new_condition = 0; vmx_check_pending_irq(v); return; From d738c00e7b64eb261afc5c4760580e2e99e12570 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:37 -0700 Subject: [PATCH 110/282] [IA64] move pgtable-nopud.h to modify from linux/ to linux-xen/. Prep for p2m traversal race fix. Signed-off-by: Isaku Yamahata --- xen/include/asm-ia64/linux-xen/asm-generic/README.origin | 8 ++++++++ .../{linux => linux-xen}/asm-generic/pgtable-nopud.h | 0 xen/include/asm-ia64/linux/asm-generic/README.origin | 1 - 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 xen/include/asm-ia64/linux-xen/asm-generic/README.origin rename xen/include/asm-ia64/{linux => linux-xen}/asm-generic/pgtable-nopud.h (100%) diff --git a/xen/include/asm-ia64/linux-xen/asm-generic/README.origin b/xen/include/asm-ia64/linux-xen/asm-generic/README.origin new file mode 100644 index 0000000000..6cd78a86fb --- /dev/null +++ b/xen/include/asm-ia64/linux-xen/asm-generic/README.origin @@ -0,0 +1,8 @@ +# Source files in this directory are near-identical copies of linux-2.6.13 +# files: + +# NOTE: ALL changes to these files should be clearly marked +# (e.g. with #ifdef XEN or XEN in a comment) so that they can be +# easily updated to future versions of the corresponding Linux files. + +pgtable-nopud.h -> linux/include/asm-generic/pgtable-nopud.h diff --git a/xen/include/asm-ia64/linux/asm-generic/pgtable-nopud.h b/xen/include/asm-ia64/linux-xen/asm-generic/pgtable-nopud.h similarity index 100% rename from xen/include/asm-ia64/linux/asm-generic/pgtable-nopud.h rename to xen/include/asm-ia64/linux-xen/asm-generic/pgtable-nopud.h diff --git a/xen/include/asm-ia64/linux/asm-generic/README.origin b/xen/include/asm-ia64/linux/asm-generic/README.origin index e1bc74c396..436f7c553f 100644 --- a/xen/include/asm-ia64/linux/asm-generic/README.origin +++ b/xen/include/asm-ia64/linux/asm-generic/README.origin @@ -9,7 +9,6 @@ ide_iops.h -> linux/include/asm-generic/ide_iops.h iomap.h -> linux/include/asm-generic/iomap.h pci.h -> linux/include/asm-generic/pci.h pgtable.h -> linux/include/asm-generic/pgtable.h -pgtable-nopud.h -> linux/include/asm-generic/pgtable-nopud.h sections.h -> linux/include/asm-generic/sections.h topology.h -> linux/include/asm-generic/topology.h unaligned.h -> linux/include/asm-generic/unaligned.h From e4bf85a69c8ab7c9315499a37c8b65826294cac7 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:42 -0700 Subject: [PATCH 111/282] [IA64] fix p2m traversing race Fixed by adding volatile to pgd_t, pud_t, pmd_t where necessary. The Xen/IA64 p2m table is lockless so that acquire semantics is necessary when traversing the p2m in order to prevent memory-reodering the following memory load. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/mm.c | 138 +++++++----------- xen/include/asm-ia64/domain.h | 2 +- .../linux-xen/asm-generic/pgtable-nopud.h | 8 + xen/include/asm-ia64/linux-xen/asm/pgalloc.h | 27 +++- xen/include/asm-ia64/linux-xen/asm/pgtable.h | 13 ++ 5 files changed, 100 insertions(+), 88 deletions(-) diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index e7b001bd17..ad26503c3e 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -249,7 +249,7 @@ try_to_clear_PGC_allocate(struct domain* d, struct page_info* page) } static void -mm_teardown_pte(struct domain* d, pte_t* pte, unsigned long offset) +mm_teardown_pte(struct domain* d, volatile pte_t* pte, unsigned long offset) { pte_t old_pte; unsigned long mfn; @@ -286,39 +286,39 @@ mm_teardown_pte(struct domain* d, pte_t* pte, unsigned long offset) } static void -mm_teardown_pmd(struct domain* d, pmd_t* pmd, unsigned long offset) +mm_teardown_pmd(struct domain* d, volatile pmd_t* pmd, unsigned long offset) { unsigned long i; - pte_t* pte = pte_offset_map(pmd, offset); + volatile pte_t* pte = pte_offset_map(pmd, offset); for (i = 0; i < PTRS_PER_PTE; i++, pte++) { - if (!pte_present(*pte)) + if (!pte_present(*pte)) // acquire semantics continue; mm_teardown_pte(d, pte, offset + (i << PAGE_SHIFT)); } } static void -mm_teardown_pud(struct domain* d, pud_t *pud, unsigned long offset) +mm_teardown_pud(struct domain* d, volatile pud_t *pud, unsigned long offset) { unsigned long i; - pmd_t *pmd = pmd_offset(pud, offset); + volatile pmd_t *pmd = pmd_offset(pud, offset); for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { - if (!pmd_present(*pmd)) + if (!pmd_present(*pmd)) // acquire semantics continue; mm_teardown_pmd(d, pmd, offset + (i << PMD_SHIFT)); } } static void -mm_teardown_pgd(struct domain* d, pgd_t *pgd, unsigned long offset) +mm_teardown_pgd(struct domain* d, volatile pgd_t *pgd, unsigned long offset) { unsigned long i; - pud_t *pud = pud_offset(pgd, offset); + volatile pud_t *pud = pud_offset(pgd, offset); for (i = 0; i < PTRS_PER_PUD; i++, pud++) { - if (!pud_present(*pud)) + if (!pud_present(*pud)) // acquire semantics continue; mm_teardown_pud(d, pud, offset + (i << PUD_SHIFT)); } @@ -329,30 +329,32 @@ mm_teardown(struct domain* d) { struct mm_struct* mm = &d->arch.mm; unsigned long i; - pgd_t* pgd; + volatile pgd_t* pgd; if (mm->pgd == NULL) return; pgd = pgd_offset(mm, 0); for (i = 0; i < PTRS_PER_PGD; i++, pgd++) { - if (!pgd_present(*pgd)) + if (!pgd_present(*pgd)) // acquire semantics continue; mm_teardown_pgd(d, pgd, i << PGDIR_SHIFT); } } static void -mm_p2m_teardown_pmd(struct domain* d, pmd_t* pmd, unsigned long offset) +mm_p2m_teardown_pmd(struct domain* d, volatile pmd_t* pmd, + unsigned long offset) { pte_free_kernel(pte_offset_map(pmd, offset)); } static void -mm_p2m_teardown_pud(struct domain* d, pud_t *pud, unsigned long offset) +mm_p2m_teardown_pud(struct domain* d, volatile pud_t *pud, + unsigned long offset) { unsigned long i; - pmd_t *pmd = pmd_offset(pud, offset); + volatile pmd_t *pmd = pmd_offset(pud, offset); for (i = 0; i < PTRS_PER_PMD; i++, pmd++) { if (!pmd_present(*pmd)) @@ -363,10 +365,11 @@ mm_p2m_teardown_pud(struct domain* d, pud_t *pud, unsigned long offset) } static void -mm_p2m_teardown_pgd(struct domain* d, pgd_t *pgd, unsigned long offset) +mm_p2m_teardown_pgd(struct domain* d, volatile pgd_t *pgd, + unsigned long offset) { unsigned long i; - pud_t *pud = pud_offset(pgd, offset); + volatile pud_t *pud = pud_offset(pgd, offset); for (i = 0; i < PTRS_PER_PUD; i++, pud++) { if (!pud_present(*pud)) @@ -381,7 +384,7 @@ mm_p2m_teardown(struct domain* d) { struct mm_struct* mm = &d->arch.mm; unsigned long i; - pgd_t* pgd; + volatile pgd_t* pgd; BUG_ON(mm->pgd == NULL); pgd = pgd_offset(mm, 0); @@ -564,38 +567,6 @@ unsigned long translate_domain_mpaddr(unsigned long mpaddr, return ((pteval & _PAGE_PPN_MASK) | (mpaddr & ~PAGE_MASK)); } -//XXX !xxx_present() should be used instread of !xxx_none()? -// __assign_new_domain_page(), assign_new_domain_page() and -// assign_new_domain0_page() are used only when domain creation. -// their accesses aren't racy so that returned pte_t doesn't need -// volatile qualifier -static pte_t* -__lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr) -{ - struct mm_struct *mm = &d->arch.mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - - BUG_ON(mm->pgd == NULL); - pgd = pgd_offset(mm, mpaddr); - if (pgd_none(*pgd)) { - pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); - } - - pud = pud_offset(pgd, mpaddr); - if (pud_none(*pud)) { - pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); - } - - pmd = pmd_offset(pud, mpaddr); - if (pmd_none(*pmd)) { - pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm, mpaddr)); - } - - return pte_offset_map(pmd, mpaddr); -} - //XXX !xxx_present() should be used instread of !xxx_none()? // pud, pmd, pte page is zero cleared when they are allocated. // Their area must be visible before population so that @@ -604,15 +575,15 @@ static volatile pte_t* lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr) { struct mm_struct *mm = &d->arch.mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; + volatile pgd_t *pgd; + volatile pud_t *pud; + volatile pmd_t *pmd; BUG_ON(mm->pgd == NULL); pgd = pgd_offset(mm, mpaddr); again_pgd: - if (unlikely(pgd_none(*pgd))) { + if (unlikely(pgd_none(*pgd))) { // acquire semantics pud_t *old_pud = NULL; pud = pud_alloc_one(mm, mpaddr); if (unlikely(!pgd_cmpxchg_rel(mm, pgd, old_pud, pud))) { @@ -623,7 +594,7 @@ lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr) pud = pud_offset(pgd, mpaddr); again_pud: - if (unlikely(pud_none(*pud))) { + if (unlikely(pud_none(*pud))) { // acquire semantics pmd_t* old_pmd = NULL; pmd = pmd_alloc_one(mm, mpaddr); if (unlikely(!pud_cmpxchg_rel(mm, pud, old_pmd, pmd))) { @@ -634,7 +605,7 @@ lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr) pmd = pmd_offset(pud, mpaddr); again_pmd: - if (unlikely(pmd_none(*pmd))) { + if (unlikely(pmd_none(*pmd))) { // acquire semantics pte_t* old_pte = NULL; pte_t* pte = pte_alloc_one_kernel(mm, mpaddr); if (unlikely(!pmd_cmpxchg_kernel_rel(mm, pmd, old_pte, pte))) { @@ -643,7 +614,7 @@ lookup_alloc_domain_pte(struct domain* d, unsigned long mpaddr) } } - return (volatile pte_t*)pte_offset_map(pmd, mpaddr); + return pte_offset_map(pmd, mpaddr); } //XXX xxx_none() should be used instread of !xxx_present()? @@ -651,48 +622,48 @@ volatile pte_t* lookup_noalloc_domain_pte(struct domain* d, unsigned long mpaddr) { struct mm_struct *mm = &d->arch.mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; + volatile pgd_t *pgd; + volatile pud_t *pud; + volatile pmd_t *pmd; BUG_ON(mm->pgd == NULL); pgd = pgd_offset(mm, mpaddr); - if (unlikely(!pgd_present(*pgd))) + if (unlikely(!pgd_present(*pgd))) // acquire semantics return NULL; pud = pud_offset(pgd, mpaddr); - if (unlikely(!pud_present(*pud))) + if (unlikely(!pud_present(*pud))) // acquire semantics return NULL; pmd = pmd_offset(pud, mpaddr); - if (unlikely(!pmd_present(*pmd))) + if (unlikely(!pmd_present(*pmd))) // acquire semantics return NULL; - return (volatile pte_t*)pte_offset_map(pmd, mpaddr); + return pte_offset_map(pmd, mpaddr); } static volatile pte_t* lookup_noalloc_domain_pte_none(struct domain* d, unsigned long mpaddr) { struct mm_struct *mm = &d->arch.mm; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; + volatile pgd_t *pgd; + volatile pud_t *pud; + volatile pmd_t *pmd; BUG_ON(mm->pgd == NULL); pgd = pgd_offset(mm, mpaddr); - if (unlikely(pgd_none(*pgd))) + if (unlikely(pgd_none(*pgd))) // acquire semantics return NULL; pud = pud_offset(pgd, mpaddr); - if (unlikely(pud_none(*pud))) + if (unlikely(pud_none(*pud))) // acquire semantics return NULL; pmd = pmd_offset(pud, mpaddr); - if (unlikely(pmd_none(*pmd))) + if (unlikely(pmd_none(*pmd))) // acquire semantics return NULL; - return (volatile pte_t*)pte_offset_map(pmd, mpaddr); + return pte_offset_map(pmd, mpaddr); } unsigned long @@ -783,7 +754,8 @@ xencomm_paddr_to_maddr(unsigned long paddr) /* Allocate a new page for domain and map it to the specified metaphysical address. */ static struct page_info * -__assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte) +__assign_new_domain_page(struct domain *d, unsigned long mpaddr, + volatile pte_t* pte) { struct page_info *p; unsigned long maddr; @@ -825,7 +797,7 @@ __assign_new_domain_page(struct domain *d, unsigned long mpaddr, pte_t* pte) struct page_info * assign_new_domain_page(struct domain *d, unsigned long mpaddr) { - pte_t *pte = __lookup_alloc_domain_pte(d, mpaddr); + volatile pte_t *pte = lookup_alloc_domain_pte(d, mpaddr); if (!pte_none(*pte)) return NULL; @@ -836,10 +808,10 @@ assign_new_domain_page(struct domain *d, unsigned long mpaddr) void assign_new_domain0_page(struct domain *d, unsigned long mpaddr) { - pte_t *pte; + volatile pte_t *pte; BUG_ON(d != dom0); - pte = __lookup_alloc_domain_pte(d, mpaddr); + pte = lookup_alloc_domain_pte(d, mpaddr); if (pte_none(*pte)) { struct page_info *p = __assign_new_domain_page(d, mpaddr, pte); if (p == NULL) { @@ -1816,7 +1788,7 @@ domain_page_mapped(struct domain* d, unsigned long mpaddr) void domain_cache_flush (struct domain *d, int sync_only) { struct mm_struct *mm = &d->arch.mm; - pgd_t *pgd = mm->pgd; + volatile pgd_t *pgd = mm->pgd; unsigned long maddr; int i,j,k, l; int nbr_page = 0; @@ -1829,22 +1801,22 @@ void domain_cache_flush (struct domain *d, int sync_only) flush_func = &flush_dcache_range; for (i = 0; i < PTRS_PER_PGD; pgd++, i++) { - pud_t *pud; - if (!pgd_present(*pgd)) + volatile pud_t *pud; + if (!pgd_present(*pgd)) // acquire semantics continue; pud = pud_offset(pgd, 0); for (j = 0; j < PTRS_PER_PUD; pud++, j++) { - pmd_t *pmd; - if (!pud_present(*pud)) + volatile pmd_t *pmd; + if (!pud_present(*pud)) // acquire semantics continue; pmd = pmd_offset(pud, 0); for (k = 0; k < PTRS_PER_PMD; pmd++, k++) { - pte_t *pte; - if (!pmd_present(*pmd)) + volatile pte_t *pte; + if (!pmd_present(*pmd)) // acquire semantics continue; pte = pte_offset_map(pmd, 0); for (l = 0; l < PTRS_PER_PTE; pte++, l++) { - if (!pte_present(*pte)) + if (!pte_present(*pte)) // acquire semantics continue; /* Convert PTE to maddr. */ maddr = __va_ul (pte_val(*pte) diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 1e9d8af21b..b327bcb27b 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -42,7 +42,7 @@ extern void panic_domain(struct pt_regs *, const char *, ...) __attribute__ ((noreturn, format (printf, 2, 3))); struct mm_struct { - pgd_t * pgd; + volatile pgd_t * pgd; // atomic_t mm_users; /* How many users with user space? */ }; diff --git a/xen/include/asm-ia64/linux-xen/asm-generic/pgtable-nopud.h b/xen/include/asm-ia64/linux-xen/asm-generic/pgtable-nopud.h index 82e29f0ce4..7e375bbdd0 100644 --- a/xen/include/asm-ia64/linux-xen/asm-generic/pgtable-nopud.h +++ b/xen/include/asm-ia64/linux-xen/asm-generic/pgtable-nopud.h @@ -35,10 +35,18 @@ static inline void pgd_clear(pgd_t *pgd) { } */ #define set_pgd(pgdptr, pgdval) set_pud((pud_t *)(pgdptr), (pud_t) { pgdval }) +#ifndef XEN static inline pud_t * pud_offset(pgd_t * pgd, unsigned long address) { return (pud_t *)pgd; } +#else +static inline volatile pud_t * +pud_offset(volatile pgd_t * pgd, unsigned long address) +{ + return (volatile pud_t *)pgd; +} +#endif #define pud_val(x) (pgd_val((x).pgd)) #define __pud(x) ((pud_t) { __pgd(x) } ) diff --git a/xen/include/asm-ia64/linux-xen/asm/pgalloc.h b/xen/include/asm-ia64/linux-xen/asm/pgalloc.h index 6e847d9ae2..9adb3b7c7e 100644 --- a/xen/include/asm-ia64/linux-xen/asm/pgalloc.h +++ b/xen/include/asm-ia64/linux-xen/asm/pgalloc.h @@ -92,10 +92,17 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm) return pgtable_quicklist_alloc(); } +#ifndef XEN static inline void pgd_free(pgd_t * pgd) { pgtable_quicklist_free(pgd); } +#else +static inline void pgd_free(volatile pgd_t * pgd) +{ + pgtable_quicklist_free((void*)pgd); +} +#endif static inline void pud_populate(struct mm_struct *mm, pud_t * pud_entry, pmd_t * pmd) @@ -105,8 +112,8 @@ pud_populate(struct mm_struct *mm, pud_t * pud_entry, pmd_t * pmd) #ifdef XEN static inline int -pud_cmpxchg_rel(struct mm_struct *mm, pud_t * pud_entry, - pmd_t * old_pmd, pmd_t * new_pmd) +pud_cmpxchg_rel(struct mm_struct *mm, volatile pud_t * pud_entry, + pmd_t * old_pmd, volatile pmd_t * new_pmd) { #ifdef CONFIG_SMP unsigned long r; @@ -127,10 +134,17 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) return pgtable_quicklist_alloc(); } +#ifndef XEN static inline void pmd_free(pmd_t * pmd) { pgtable_quicklist_free(pmd); } +#else +static inline void pmd_free(volatile pmd_t * pmd) +{ + pgtable_quicklist_free((void*)pmd); +} +#endif #define __pmd_free_tlb(tlb, pmd) pmd_free(pmd) @@ -150,7 +164,7 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte) #ifdef XEN static inline int -pmd_cmpxchg_kernel_rel(struct mm_struct *mm, pmd_t * pmd_entry, +pmd_cmpxchg_kernel_rel(struct mm_struct *mm, volatile pmd_t * pmd_entry, pte_t * old_pte, pte_t * new_pte) { #ifdef CONFIG_SMP @@ -186,12 +200,17 @@ static inline void pte_free(struct page *pte) { pgtable_quicklist_free(page_address(pte)); } -#endif static inline void pte_free_kernel(pte_t * pte) { pgtable_quicklist_free(pte); } +#else +static inline void pte_free_kernel(volatile pte_t * pte) +{ + pgtable_quicklist_free((void*)pte); +} +#endif #ifndef XEN #define __pte_free_tlb(tlb, pte) pte_free(pte) diff --git a/xen/include/asm-ia64/linux-xen/asm/pgtable.h b/xen/include/asm-ia64/linux-xen/asm/pgtable.h index a859a8b437..306151d152 100644 --- a/xen/include/asm-ia64/linux-xen/asm/pgtable.h +++ b/xen/include/asm-ia64/linux-xen/asm/pgtable.h @@ -380,7 +380,11 @@ pgd_index (unsigned long address) /* The offset in the 1-level directory is given by the 3 region bits (61..63) and the level-1 bits. */ +#ifndef XEN static inline pgd_t* +#else +static inline volatile pgd_t* +#endif pgd_offset (struct mm_struct *mm, unsigned long address) { return mm->pgd + pgd_index(address); @@ -397,15 +401,24 @@ pgd_offset (struct mm_struct *mm, unsigned long address) #define pgd_offset_gate(mm, addr) pgd_offset_k(addr) /* Find an entry in the second-level page table.. */ +#ifndef XEN #define pmd_offset(dir,addr) \ ((pmd_t *) pud_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) +#else +#define pmd_offset(dir,addr) \ + ((volatile pmd_t *) pud_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) +#endif /* * Find an entry in the third-level page table. This looks more complicated than it * should be because some platforms place page tables in high memory. */ #define pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#ifndef XEN #define pte_offset_kernel(dir,addr) ((pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr)) +#else +#define pte_offset_kernel(dir,addr) ((volatile pte_t *) pmd_page_kernel(*(dir)) + pte_index(addr)) +#endif #define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr) #define pte_offset_map_nested(dir,addr) pte_offset_map(dir, addr) #define pte_unmap(pte) do { } while (0) From fb66f86a4cc4416ce62e31703d5fdb386ead179b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:47 -0700 Subject: [PATCH 112/282] [IA64] HVM domains need to trigger do_softirq for PAL_HALT_LIGHT too call do_softirq() to enter scheduler when VTI does PAL_HALT_LIGHT, like xen-ia64-unstable.hg changeset: 12520:bcd2960d6dfd018de58fc0113c37d30edbe802c5 Signed-off-by: Zhang Xin --- xen/arch/ia64/xen/fw_emul.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c index f5eb0c7682..6dc9ea4f8a 100644 --- a/xen/arch/ia64/xen/fw_emul.c +++ b/xen/arch/ia64/xen/fw_emul.c @@ -32,6 +32,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(efi_time_services_lock); @@ -611,8 +612,10 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) case PAL_HALT_LIGHT: if (VMX_DOMAIN(current)) { /* Called by VTI. */ - if (!is_unmasked_irq(current)) + if (!is_unmasked_irq(current)) { do_sched_op_compat(SCHEDOP_block, 0); + do_softirq(); + } status = PAL_STATUS_SUCCESS; } break; From ab7d6fd1157e1a07fba7eccd7123e650126fc171 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:51 -0700 Subject: [PATCH 113/282] [IA64] Fix for viosapic interrupts Fix xen-ia64-unstable.hg cset 12662 for viosapic code. Signed-off-by: Alex Williamson --- xen/arch/ia64/vmx/vmx_process.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xen/arch/ia64/vmx/vmx_process.c b/xen/arch/ia64/vmx/vmx_process.c index d6c5c295d1..0aaef9a7c7 100644 --- a/xen/arch/ia64/vmx/vmx_process.c +++ b/xen/arch/ia64/vmx/vmx_process.c @@ -227,8 +227,7 @@ void leave_hypervisor_tail(struct pt_regs *regs) d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; if (callback_irq != 0) { /* change level for para-device callback irq */ - vmx_vioapic_set_irq(d, callback_irq, - local_events_need_delivery()); + viosapic_set_irq(d, callback_irq, local_events_need_delivery()); } } From fcb3c0591c1e55f049d255f55a51606eac53fb10 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:57:55 -0700 Subject: [PATCH 114/282] [IA64] Fix failure when Xen is booted with "nomca" Based on patch from Kazuhiro Suzuki Signed-off-by: Alex williamson --- xen/arch/ia64/linux-xen/mca.c | 17 ++++++++++------- xen/arch/ia64/xen/fw_emul.c | 2 +- xen/include/asm-ia64/xenmca.h | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c index cf43c17cb8..8715ef1d5e 100644 --- a/xen/arch/ia64/linux-xen/mca.c +++ b/xen/arch/ia64/linux-xen/mca.c @@ -206,8 +206,8 @@ static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES]; #define IA64_LOG_COUNT(it) ia64_state_log[it].isl_count #ifdef XEN -struct list_head sal_queue[IA64_MAX_LOG_TYPES]; -sal_log_record_header_t *sal_record = NULL; +struct list_head *sal_queue, sal_log_queues[IA64_MAX_LOG_TYPES]; +sal_log_record_header_t *sal_record; DEFINE_SPINLOCK(sal_queue_lock); #endif @@ -1606,7 +1606,7 @@ ia64_mca_cpu_init(void *cpu_data) } } #ifdef XEN - else { + else if (sal_queue) { int i; for (i = 0; i < IA64_MAX_LOG_TYPES; i++) ia64_log_queue(i, 0); @@ -1811,10 +1811,13 @@ ia64_mca_init(void) ia64_log_init(SAL_INFO_TYPE_CPE); #ifdef XEN - INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_MCA]); - INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_INIT]); - INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_CMC]); - INIT_LIST_HEAD(&sal_queue[SAL_INFO_TYPE_CPE]); + INIT_LIST_HEAD(&sal_log_queues[SAL_INFO_TYPE_MCA]); + INIT_LIST_HEAD(&sal_log_queues[SAL_INFO_TYPE_INIT]); + INIT_LIST_HEAD(&sal_log_queues[SAL_INFO_TYPE_CMC]); + INIT_LIST_HEAD(&sal_log_queues[SAL_INFO_TYPE_CPE]); + + /* NULL sal_queue used elsewhere to determine MCA init state */ + sal_queue = sal_log_queues; open_softirq(CMC_DISABLE_SOFTIRQ, (softirq_handler)ia64_mca_cmc_vector_disable); diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c index 6dc9ea4f8a..e539224cd2 100644 --- a/xen/arch/ia64/xen/fw_emul.c +++ b/xen/arch/ia64/xen/fw_emul.c @@ -214,7 +214,7 @@ sal_emulator (long index, unsigned long in1, unsigned long in2, struct smp_call_args_t arg; spin_lock_irqsave(&sal_queue_lock, flags); - if (list_empty(&sal_queue[in1])) { + if (!sal_queue || list_empty(&sal_queue[in1])) { sal_log_record_header_t header; XEN_GUEST_HANDLE(void) handle = *(XEN_GUEST_HANDLE(void)*)&in3; diff --git a/xen/include/asm-ia64/xenmca.h b/xen/include/asm-ia64/xenmca.h index c541b237be..653253e8fd 100644 --- a/xen/include/asm-ia64/xenmca.h +++ b/xen/include/asm-ia64/xenmca.h @@ -21,7 +21,7 @@ typedef struct sal_queue_entry_t { struct list_head list; } sal_queue_entry_t; -extern struct list_head sal_queue[]; +extern struct list_head *sal_queue; struct ia64_mca_tlb_info { u64 cr_lid; From 0ff991fda33ceef1cb798ed35b676587fdc558a2 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Thu, 30 Nov 2006 15:58:21 -0700 Subject: [PATCH 115/282] [IA64] Make do_ssc() not fall into an infinite loop Instead, call panic_domain(). Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/fw_emul.c | 6 +++--- xen/include/asm-ia64/debugger.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c index e539224cd2..2a9f8fcb53 100644 --- a/xen/arch/ia64/xen/fw_emul.c +++ b/xen/arch/ia64/xen/fw_emul.c @@ -1201,9 +1201,9 @@ if (!running_on_sim) { printk("SSC_OPEN, not implemented on hardware. (ignoring vcpu_set_gr(current,8,-1L,0); break; default: - printk("ia64_handle_break: bad ssc code %lx, iip=0x%lx, b0=0x%lx... spinning\n", - ssc, regs->cr_iip, regs->b0); - while(1); + panic_domain(regs, + "%s: bad ssc code %lx, iip=0x%lx, b0=0x%lx\n", + __func__, ssc, regs->cr_iip, regs->b0); break; } vcpu_increment_iip(current); diff --git a/xen/include/asm-ia64/debugger.h b/xen/include/asm-ia64/debugger.h index 104cea9bfc..3e6a51d2e4 100644 --- a/xen/include/asm-ia64/debugger.h +++ b/xen/include/asm-ia64/debugger.h @@ -23,11 +23,13 @@ #define __ASM_DEBUGGER_H__ // this number is an arbitary number which is not used for any other purpose +// __builtin_trap() 0x0 // ski 0x80001, 0x80002 // kdb 0x80100, 0x80101 // kprobe 0x80200, jprobe 0x80300 // kgdb 0x6665 // gdb 0x99998 (#define IA64_BREAKPOINT 0x00003333300LL) +// ltrace 0x80001 (NOTE: this conflicts ski) // cdb should handle 0 and CDB_BREAK_NUM. #define CDB_BREAK_NUM 0x80800 From b4f5b27478ed1a82018f28dbd2a696701a286052 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Fri, 1 Dec 2006 09:28:14 +0000 Subject: [PATCH 116/282] [XEN] Fix error paths in p2m insertion code Signed-off-by: Tim Deegan --- xen/arch/x86/mm/shadow/common.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 8bf43133e4..d71704cbd2 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1008,12 +1008,13 @@ shadow_set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) void *table = sh_map_domain_page(table_mfn); unsigned long gfn_remainder = gfn; l1_pgentry_t *p2m_entry; + int rv=0; #if CONFIG_PAGING_LEVELS >= 4 if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn, L4_PAGETABLE_SHIFT - PAGE_SHIFT, L4_PAGETABLE_ENTRIES, PGT_l3_page_table) ) - return 0; + goto out; #endif #if CONFIG_PAGING_LEVELS >= 3 // When using PAE Xen, we only allow 33 bits of pseudo-physical @@ -1027,12 +1028,12 @@ shadow_set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) ? 8 : L3_PAGETABLE_ENTRIES), PGT_l2_page_table) ) - return 0; + goto out; #endif if ( !p2m_next_level(d, &table_mfn, &table, &gfn_remainder, gfn, L2_PAGETABLE_SHIFT - PAGE_SHIFT, L2_PAGETABLE_ENTRIES, PGT_l1_page_table) ) - return 0; + goto out; p2m_entry = p2m_find_entry(table, &gfn_remainder, gfn, 0, L1_PAGETABLE_ENTRIES); @@ -1051,9 +1052,12 @@ shadow_set_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) (void)__shadow_validate_guest_entry( d->vcpu[0], table_mfn, p2m_entry, sizeof(*p2m_entry)); + /* Success */ + rv = 1; + + out: sh_unmap_domain_page(table); - - return 1; + return rv; } // Allocate a new p2m table for a domain. From 5ccf78fdd9a2728d6cd88d1b2c1f800c00589a77 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 09:48:18 +0000 Subject: [PATCH 117/282] [HVM][VMX] Fix for CR8 acceleration on 64bit guest. For current CR8 acceleration, we do not call update_tpr_threshold() at every VMEXIT. But at some situations, we cannot inject guest interrupts in time. And at some critical time, it will bring up a blue screen to 64bit Windows guest. Now, we select to call update_tpr_threshold() at very VMEXIT time. It's safe, and we do not see clear performance downgrade so far. Signed-off-by: Xiaohui Xin xiaohui.xin@intel.com --- xen/arch/x86/hvm/vlapic.c | 9 --------- xen/arch/x86/hvm/vmx/io.c | 8 +------- xen/arch/x86/hvm/vmx/vmx.c | 1 - xen/include/asm-x86/hvm/vlapic.h | 1 - 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 1c6bef005e..60e6171c47 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -119,19 +119,16 @@ static int vlapic_find_highest_vector(u32 *bitmap) static int vlapic_test_and_set_irr(int vector, struct vlapic *vlapic) { - vlapic->flush_tpr_threshold = 1; return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR); } static void vlapic_set_irr(int vector, struct vlapic *vlapic) { - vlapic->flush_tpr_threshold = 1; vlapic_set_vector(vector, vlapic->regs + APIC_IRR); } static void vlapic_clear_irr(int vector, struct vlapic *vlapic) { - vlapic->flush_tpr_threshold = 1; vlapic_clear_vector(vector, vlapic->regs + APIC_IRR); } @@ -634,7 +631,6 @@ static void vlapic_write(struct vcpu *v, unsigned long address, { case APIC_TASKPRI: vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff); - vlapic->flush_tpr_threshold = 1; break; case APIC_EOI: @@ -667,10 +663,7 @@ static void vlapic_write(struct vcpu *v, unsigned long address, } } else - { vlapic->disabled &= ~VLAPIC_SW_DISABLED; - vlapic->flush_tpr_threshold = 1; - } break; case APIC_ESR: @@ -925,8 +918,6 @@ static int vlapic_reset(struct vlapic *vlapic) vlapic_set_reg(vlapic, APIC_SPIV, 0xff); vlapic->disabled |= VLAPIC_SW_DISABLED; - vlapic->flush_tpr_threshold = 1; - return 1; } diff --git a/xen/arch/x86/hvm/vmx/io.c b/xen/arch/x86/hvm/vmx/io.c index 2f3cf623b1..662a6697a0 100644 --- a/xen/arch/x86/hvm/vmx/io.c +++ b/xen/arch/x86/hvm/vmx/io.c @@ -71,10 +71,6 @@ static void update_tpr_threshold(struct vlapic *vlapic) { int max_irr, tpr; - /* Clear the work-to-do flag /then/ do the work. */ - vlapic->flush_tpr_threshold = 0; - mb(); - if ( !vlapic_enabled(vlapic) || ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) ) { @@ -95,7 +91,6 @@ asmlinkage void vmx_intr_assist(void) int highest_vector; unsigned long eflags; struct vcpu *v = current; - struct vlapic *vlapic = vcpu_vlapic(v); struct hvm_domain *plat=&v->domain->arch.hvm_domain; struct periodic_time *pt = &plat->pl_time.periodic_tm; unsigned int idtv_info_field; @@ -110,8 +105,7 @@ asmlinkage void vmx_intr_assist(void) hvm_set_callback_irq_level(); - if ( vlapic->flush_tpr_threshold ) - update_tpr_threshold(vlapic); + update_tpr_threshold(vcpu_vlapic(v)); has_ext_irq = cpu_has_pending_irq(v); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 7d226e6ba1..58cca4bea4 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -2500,7 +2500,6 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs *regs) break; case EXIT_REASON_TPR_BELOW_THRESHOLD: - vcpu_vlapic(v)->flush_tpr_threshold = 1; break; default: diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index 003d93b389..2053fc56ec 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -54,7 +54,6 @@ struct vlapic { uint32_t timer_divisor; struct timer vlapic_timer; int timer_pending_count; - int flush_tpr_threshold; s_time_t timer_last_update; struct page_info *regs_page; void *regs; From a5ae44fcdf672966b1b31949dd3a142f75e7f90a Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 09:48:32 +0000 Subject: [PATCH 118/282] This is Anthony Liguori's virtual framebuffer forward ported and extensively hacked based on feedback from xen-devel. Its architecture is comparable to the common split device driver architecture: xenfb and xenkbd modules serve as frontend in domU, and the user space vncfb or sdlfb process serves as backend in dom0. Signed-off-by: Markus Armbruster Signed-off-by: Anthony Liguori --- .../arch/i386/kernel/setup-xen.c | 5 +- linux-2.6-xen-sparse/arch/ia64/kernel/setup.c | 4 +- .../arch/x86_64/kernel/setup-xen.c | 7 +- linux-2.6-xen-sparse/drivers/char/tty_io.c | 3264 ----------------- linux-2.6-xen-sparse/drivers/xen/Kconfig | 23 + linux-2.6-xen-sparse/drivers/xen/Makefile | 2 + .../drivers/xen/console/console.c | 10 + .../drivers/xen/fbfront/Makefile | 2 + .../drivers/xen/fbfront/xenfb.c | 682 ++++ .../drivers/xen/fbfront/xenkbd.c | 300 ++ linux-2.6-xen-sparse/mm/memory.c | 1 + tools/Makefile | 1 + tools/python/xen/xend/XendDevices.py | 4 +- tools/python/xen/xend/XendDomainInfo.py | 19 +- tools/python/xen/xend/image.py | 74 + tools/python/xen/xend/server/vfbif.py | 29 + tools/python/xen/xm/create.py | 34 +- tools/xenfb/Makefile | 35 + tools/xenfb/sdlfb.c | 334 ++ tools/xenfb/vncfb.c | 393 ++ tools/xenfb/xenfb.c | 691 ++++ tools/xenfb/xenfb.h | 34 + xen/include/public/io/fbif.h | 116 + xen/include/public/io/kbdif.h | 108 + 24 files changed, 2895 insertions(+), 3277 deletions(-) delete mode 100644 linux-2.6-xen-sparse/drivers/char/tty_io.c create mode 100644 linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile create mode 100644 linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c create mode 100644 linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c create mode 100644 tools/python/xen/xend/server/vfbif.py create mode 100644 tools/xenfb/Makefile create mode 100644 tools/xenfb/sdlfb.c create mode 100644 tools/xenfb/vncfb.c create mode 100644 tools/xenfb/xenfb.c create mode 100644 tools/xenfb/xenfb.h create mode 100644 xen/include/public/io/fbif.h create mode 100644 xen/include/public/io/kbdif.h diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c index 252e5c4ec2..e8a96c7c6d 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c @@ -1867,8 +1867,9 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif } } diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c index 8f15b3001c..76d4b8824b 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c @@ -550,9 +550,9 @@ setup_arch (char **cmdline_p) xen_start_info->nr_pages, xen_start_info->flags); if (!is_initial_xendomain()) { - extern int console_use_vt; +#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE) conswitchp = NULL; - console_use_vt = 0; +#endif } } #endif diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c index 5c630cac9e..3bc217a8c6 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c @@ -983,9 +983,10 @@ void __init setup_arch(char **cmdline_p) #endif #endif } else { - extern int console_use_vt; - console_use_vt = 0; - } +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif + } } #else /* CONFIG_XEN */ diff --git a/linux-2.6-xen-sparse/drivers/char/tty_io.c b/linux-2.6-xen-sparse/drivers/char/tty_io.c deleted file mode 100644 index 0372d93bca..0000000000 --- a/linux-2.6-xen-sparse/drivers/char/tty_io.c +++ /dev/null @@ -1,3264 +0,0 @@ -/* - * linux/drivers/char/tty_io.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles - * or rs-channels. It also implements echoing, cooked mode etc. - * - * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. - * - * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the - * tty_struct and tty_queue structures. Previously there was an array - * of 256 tty_struct's which was statically allocated, and the - * tty_queue structures were allocated at boot time. Both are now - * dynamically allocated only when the tty is open. - * - * Also restructured routines so that there is more of a separation - * between the high-level tty routines (tty_io.c and tty_ioctl.c) and - * the low-level tty routines (serial.c, pty.c, console.c). This - * makes for cleaner and more compact code. -TYT, 9/17/92 - * - * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines - * which can be dynamically activated and de-activated by the line - * discipline handling modules (like SLIP). - * - * NOTE: pay no attention to the line discipline code (yet); its - * interface is still subject to change in this version... - * -- TYT, 1/31/92 - * - * Added functionality to the OPOST tty handling. No delays, but all - * other bits should be there. - * -- Nick Holloway , 27th May 1993. - * - * Rewrote canonical mode and added more termios flags. - * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 - * - * Reorganized FASYNC support so mouse code can share it. - * -- ctm@ardi.com, 9Sep95 - * - * New TIOCLINUX variants added. - * -- mj@k332.feld.cvut.cz, 19-Nov-95 - * - * Restrict vt switching via ioctl() - * -- grif@cs.ucr.edu, 5-Dec-95 - * - * Move console and virtual terminal code to more appropriate files, - * implement CONFIG_VT and generalize console device interface. - * -- Marko Kohtala , March 97 - * - * Rewrote init_dev and release_dev to eliminate races. - * -- Bill Hawes , June 97 - * - * Added devfs support. - * -- C. Scott Ananian , 13-Jan-1998 - * - * Added support for a Unix98-style ptmx device. - * -- C. Scott Ananian , 14-Jan-1998 - * - * Reduced memory usage for older ARM systems - * -- Russell King - * - * Move do_SAK() into process context. Less stack use in devfs functions. - * alloc_tty_struct() always uses kmalloc() -- Andrew Morton 17Mar01 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#undef TTY_DEBUG_HANGUP - -#define TTY_PARANOIA_CHECK 1 -#define CHECK_TTY_COUNT 1 - -struct termios tty_std_termios = { /* for the benefit of tty drivers */ - .c_iflag = ICRNL | IXON, - .c_oflag = OPOST | ONLCR, - .c_cflag = B38400 | CS8 | CREAD | HUPCL, - .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | - ECHOCTL | ECHOKE | IEXTEN, - .c_cc = INIT_C_CC -}; - -EXPORT_SYMBOL(tty_std_termios); - -/* This list gets poked at by procfs and various bits of boot up code. This - could do with some rationalisation such as pulling the tty proc function - into this file */ - -LIST_HEAD(tty_drivers); /* linked list of tty drivers */ - -/* Semaphore to protect creating and releasing a tty. This is shared with - vt.c for deeply disgusting hack reasons */ -DECLARE_MUTEX(tty_sem); - -int console_use_vt = 1; - -#ifdef CONFIG_UNIX98_PTYS -extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ -extern int pty_limit; /* Config limit on Unix98 ptys */ -static DEFINE_IDR(allocated_ptys); -static DECLARE_MUTEX(allocated_ptys_lock); -static int ptmx_open(struct inode *, struct file *); -#endif - -extern void disable_early_printk(void); - -static void initialize_tty_struct(struct tty_struct *tty); - -static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); -static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); -ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *); -static unsigned int tty_poll(struct file *, poll_table *); -static int tty_open(struct inode *, struct file *); -static int tty_release(struct inode *, struct file *); -int tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg); -static int tty_fasync(int fd, struct file * filp, int on); -static void release_mem(struct tty_struct *tty, int idx); - - -static struct tty_struct *alloc_tty_struct(void) -{ - struct tty_struct *tty; - - tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); - if (tty) - memset(tty, 0, sizeof(struct tty_struct)); - return tty; -} - -static void tty_buffer_free_all(struct tty_struct *); - -static inline void free_tty_struct(struct tty_struct *tty) -{ - kfree(tty->write_buf); - tty_buffer_free_all(tty); - kfree(tty); -} - -#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) - -char *tty_name(struct tty_struct *tty, char *buf) -{ - if (!tty) /* Hmm. NULL pointer. That's fun. */ - strcpy(buf, "NULL tty"); - else - strcpy(buf, tty->name); - return buf; -} - -EXPORT_SYMBOL(tty_name); - -int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, - const char *routine) -{ -#ifdef TTY_PARANOIA_CHECK - if (!tty) { - printk(KERN_WARNING - "null TTY for (%d:%d) in %s\n", - imajor(inode), iminor(inode), routine); - return 1; - } - if (tty->magic != TTY_MAGIC) { - printk(KERN_WARNING - "bad magic number for tty struct (%d:%d) in %s\n", - imajor(inode), iminor(inode), routine); - return 1; - } -#endif - return 0; -} - -static int check_tty_count(struct tty_struct *tty, const char *routine) -{ -#ifdef CHECK_TTY_COUNT - struct list_head *p; - int count = 0; - - file_list_lock(); - list_for_each(p, &tty->tty_files) { - count++; - } - file_list_unlock(); - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_SLAVE && - tty->link && tty->link->count) - count++; - if (tty->count != count) { - printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " - "!= #fd's(%d) in %s\n", - tty->name, tty->count, count, routine); - return count; - } -#endif - return 0; -} - -/* - * Tty buffer allocation management - */ - -static void tty_buffer_free_all(struct tty_struct *tty) -{ - struct tty_buffer *thead; - while((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; - kfree(thead); - } - while((thead = tty->buf.free) != NULL) { - tty->buf.free = thead->next; - kfree(thead); - } - tty->buf.tail = NULL; -} - -static void tty_buffer_init(struct tty_struct *tty) -{ - spin_lock_init(&tty->buf.lock); - tty->buf.head = NULL; - tty->buf.tail = NULL; - tty->buf.free = NULL; -} - -static struct tty_buffer *tty_buffer_alloc(size_t size) -{ - struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); - if(p == NULL) - return NULL; - p->used = 0; - p->size = size; - p->next = NULL; - p->active = 0; - p->commit = 0; - p->read = 0; - p->char_buf_ptr = (char *)(p->data); - p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; -/* printk("Flip create %p\n", p); */ - return p; -} - -/* Must be called with the tty_read lock held. This needs to acquire strategy - code to decide if we should kfree or relink a given expired buffer */ - -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) -{ - /* Dumb strategy for now - should keep some stats */ -/* printk("Flip dispose %p\n", b); */ - if(b->size >= 512) - kfree(b); - else { - b->next = tty->buf.free; - tty->buf.free = b; - } -} - -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) -{ - struct tty_buffer **tbh = &tty->buf.free; - while((*tbh) != NULL) { - struct tty_buffer *t = *tbh; - if(t->size >= size) { - *tbh = t->next; - t->next = NULL; - t->used = 0; - t->commit = 0; - t->read = 0; - /* DEBUG ONLY */ -/* memset(t->data, '*', size); */ -/* printk("Flip recycle %p\n", t); */ - return t; - } - tbh = &((*tbh)->next); - } - /* Round the buffer size out */ - size = (size + 0xFF) & ~ 0xFF; - return tty_buffer_alloc(size); - /* Should possibly check if this fails for the largest buffer we - have queued and recycle that ? */ -} - -int tty_buffer_request_room(struct tty_struct *tty, size_t size) -{ - struct tty_buffer *b, *n; - int left; - unsigned long flags; - - spin_lock_irqsave(&tty->buf.lock, flags); - - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ - if ((b = tty->buf.tail) != NULL) { - left = b->size - b->used; - b->active = 1; - } else - left = 0; - - if (left < size) { - /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_find(tty, size)) != NULL) { - if (b != NULL) { - b->next = n; - b->active = 0; - b->commit = b->used; - } else - tty->buf.head = n; - tty->buf.tail = n; - n->active = 1; - } else - size = left; - } - - spin_unlock_irqrestore(&tty->buf.lock, flags); - return size; -} - -EXPORT_SYMBOL_GPL(tty_buffer_request_room); - -int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size) -{ - int copied = 0; - do { - int space = tty_buffer_request_room(tty, size - copied); - struct tty_buffer *tb = tty->buf.tail; - /* If there is no space then tb may be NULL */ - if(unlikely(space == 0)) - break; - memcpy(tb->char_buf_ptr + tb->used, chars, space); - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; - copied += space; - chars += space; -/* printk("Flip insert %d.\n", space); */ - } - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - while (unlikely(size > copied)); - return copied; -} - -EXPORT_SYMBOL_GPL(tty_insert_flip_string); - -int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size) -{ - int copied = 0; - do { - int space = tty_buffer_request_room(tty, size - copied); - struct tty_buffer *tb = tty->buf.tail; - /* If there is no space then tb may be NULL */ - if(unlikely(space == 0)) - break; - memcpy(tb->char_buf_ptr + tb->used, chars, space); - memcpy(tb->flag_buf_ptr + tb->used, flags, space); - tb->used += space; - copied += space; - chars += space; - flags += space; - } - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - while (unlikely(size > copied)); - return copied; -} - -EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); - - -/* - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for normal characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - */ - -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) -{ - int space = tty_buffer_request_room(tty, size); - if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; - } - return space; -} - -EXPORT_SYMBOL_GPL(tty_prepare_flip_string); - -/* - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - */ - -int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) -{ - int space = tty_buffer_request_room(tty, size); - if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - *flags = tb->flag_buf_ptr + tb->used; - tb->used += space; - } - return space; -} - -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); - - - -/* - * This is probably overkill for real world processors but - * they are not on hot paths so a little discipline won't do - * any harm. - */ - -static void tty_set_termios_ldisc(struct tty_struct *tty, int num) -{ - down(&tty->termios_sem); - tty->termios->c_line = num; - up(&tty->termios_sem); -} - -/* - * This guards the refcounted line discipline lists. The lock - * must be taken with irqs off because there are hangup path - * callers who will do ldisc lookups and cannot sleep. - */ - -static DEFINE_SPINLOCK(tty_ldisc_lock); -static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ - -int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) -{ - unsigned long flags; - int ret = 0; - - if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; - - spin_lock_irqsave(&tty_ldisc_lock, flags); - tty_ldiscs[disc] = *new_ldisc; - tty_ldiscs[disc].num = disc; - tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - tty_ldiscs[disc].refcount = 0; - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - - return ret; -} -EXPORT_SYMBOL(tty_register_ldisc); - -int tty_unregister_ldisc(int disc) -{ - unsigned long flags; - int ret = 0; - - if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; - - spin_lock_irqsave(&tty_ldisc_lock, flags); - if (tty_ldiscs[disc].refcount) - ret = -EBUSY; - else - tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - - return ret; -} -EXPORT_SYMBOL(tty_unregister_ldisc); - -struct tty_ldisc *tty_ldisc_get(int disc) -{ - unsigned long flags; - struct tty_ldisc *ld; - - if (disc < N_TTY || disc >= NR_LDISCS) - return NULL; - - spin_lock_irqsave(&tty_ldisc_lock, flags); - - ld = &tty_ldiscs[disc]; - /* Check the entry is defined */ - if(ld->flags & LDISC_FLAG_DEFINED) - { - /* If the module is being unloaded we can't use it */ - if (!try_module_get(ld->owner)) - ld = NULL; - else /* lock it */ - ld->refcount++; - } - else - ld = NULL; - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return ld; -} - -EXPORT_SYMBOL_GPL(tty_ldisc_get); - -void tty_ldisc_put(int disc) -{ - struct tty_ldisc *ld; - unsigned long flags; - - if (disc < N_TTY || disc >= NR_LDISCS) - BUG(); - - spin_lock_irqsave(&tty_ldisc_lock, flags); - ld = &tty_ldiscs[disc]; - if(ld->refcount == 0) - BUG(); - ld->refcount --; - module_put(ld->owner); - spin_unlock_irqrestore(&tty_ldisc_lock, flags); -} - -EXPORT_SYMBOL_GPL(tty_ldisc_put); - -static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) -{ - tty->ldisc = *ld; - tty->ldisc.refcount = 0; -} - -/** - * tty_ldisc_try - internal helper - * @tty: the tty - * - * Make a single attempt to grab and bump the refcount on - * the tty ldisc. Return 0 on failure or 1 on success. This is - * used to implement both the waiting and non waiting versions - * of tty_ldisc_ref - */ - -static int tty_ldisc_try(struct tty_struct *tty) -{ - unsigned long flags; - struct tty_ldisc *ld; - int ret = 0; - - spin_lock_irqsave(&tty_ldisc_lock, flags); - ld = &tty->ldisc; - if(test_bit(TTY_LDISC, &tty->flags)) - { - ld->refcount++; - ret = 1; - } - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - return ret; -} - -/** - * tty_ldisc_ref_wait - wait for the tty ldisc - * @tty: tty device - * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then - * wait patiently until it changes. - * - * Note: Must not be called from an IRQ/timer context. The caller - * must also be careful not to hold other locks that will deadlock - * against a discipline change, such as an existing ldisc reference - * (which we check for) - */ - -struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) -{ - /* wait_event is a macro */ - wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); - if(tty->ldisc.refcount == 0) - printk(KERN_ERR "tty_ldisc_ref_wait\n"); - return &tty->ldisc; -} - -EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); - -/** - * tty_ldisc_ref - get the tty ldisc - * @tty: tty device - * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then - * return NULL. Can be called from IRQ and timer functions. - */ - -struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) -{ - if(tty_ldisc_try(tty)) - return &tty->ldisc; - return NULL; -} - -EXPORT_SYMBOL_GPL(tty_ldisc_ref); - -/** - * tty_ldisc_deref - free a tty ldisc reference - * @ld: reference to free up - * - * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May - * be called in IRQ context. - */ - -void tty_ldisc_deref(struct tty_ldisc *ld) -{ - unsigned long flags; - - if(ld == NULL) - BUG(); - - spin_lock_irqsave(&tty_ldisc_lock, flags); - if(ld->refcount == 0) - printk(KERN_ERR "tty_ldisc_deref: no references.\n"); - else - ld->refcount--; - if(ld->refcount == 0) - wake_up(&tty_ldisc_wait); - spin_unlock_irqrestore(&tty_ldisc_lock, flags); -} - -EXPORT_SYMBOL_GPL(tty_ldisc_deref); - -/** - * tty_ldisc_enable - allow ldisc use - * @tty: terminal to activate ldisc on - * - * Set the TTY_LDISC flag when the line discipline can be called - * again. Do neccessary wakeups for existing sleepers. - * - * Note: nobody should set this bit except via this function. Clearing - * directly is allowed. - */ - -static void tty_ldisc_enable(struct tty_struct *tty) -{ - set_bit(TTY_LDISC, &tty->flags); - wake_up(&tty_ldisc_wait); -} - -/** - * tty_set_ldisc - set line discipline - * @tty: the terminal to set - * @ldisc: the line discipline - * - * Set the discipline of a tty line. Must be called from a process - * context. - */ - -static int tty_set_ldisc(struct tty_struct *tty, int ldisc) -{ - int retval = 0; - struct tty_ldisc o_ldisc; - char buf[64]; - int work; - unsigned long flags; - struct tty_ldisc *ld; - struct tty_struct *o_tty; - - if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) - return -EINVAL; - -restart: - - ld = tty_ldisc_get(ldisc); - /* Eduardo Blanco */ - /* Cyrus Durgin */ - if (ld == NULL) { - request_module("tty-ldisc-%d", ldisc); - ld = tty_ldisc_get(ldisc); - } - if (ld == NULL) - return -EINVAL; - - /* - * No more input please, we are switching. The new ldisc - * will update this value in the ldisc open function - */ - - tty->receive_room = 0; - - /* - * Problem: What do we do if this blocks ? - */ - - tty_wait_until_sent(tty, 0); - - if (tty->ldisc.num == ldisc) { - tty_ldisc_put(ldisc); - return 0; - } - - o_ldisc = tty->ldisc; - o_tty = tty->link; - - /* - * Make sure we don't change while someone holds a - * reference to the line discipline. The TTY_LDISC bit - * prevents anyone taking a reference once it is clear. - * We need the lock to avoid racing reference takers. - */ - - spin_lock_irqsave(&tty_ldisc_lock, flags); - if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { - if(tty->ldisc.refcount) { - /* Free the new ldisc we grabbed. Must drop the lock - first. */ - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(ldisc); - /* - * There are several reasons we may be busy, including - * random momentary I/O traffic. We must therefore - * retry. We could distinguish between blocking ops - * and retries if we made tty_ldisc_wait() smarter. That - * is up for discussion. - */ - if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) - return -ERESTARTSYS; - goto restart; - } - if(o_tty && o_tty->ldisc.refcount) { - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(ldisc); - if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) - return -ERESTARTSYS; - goto restart; - } - } - - /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */ - - if (!test_bit(TTY_LDISC, &tty->flags)) { - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - tty_ldisc_put(ldisc); - ld = tty_ldisc_ref_wait(tty); - tty_ldisc_deref(ld); - goto restart; - } - - clear_bit(TTY_LDISC, &tty->flags); - clear_bit(TTY_DONT_FLIP, &tty->flags); - if (o_tty) { - clear_bit(TTY_LDISC, &o_tty->flags); - clear_bit(TTY_DONT_FLIP, &o_tty->flags); - } - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - - /* - * From this point on we know nobody has an ldisc - * usage reference, nor can they obtain one until - * we say so later on. - */ - - work = cancel_delayed_work(&tty->buf.work); - /* - * Wait for ->hangup_work and ->buf.work handlers to terminate - */ - - flush_scheduled_work(); - /* Shutdown the current discipline. */ - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - - /* Now set up the new line discipline. */ - tty_ldisc_assign(tty, ld); - tty_set_termios_ldisc(tty, ldisc); - if (tty->ldisc.open) - retval = (tty->ldisc.open)(tty); - if (retval < 0) { - tty_ldisc_put(ldisc); - /* There is an outstanding reference here so this is safe */ - tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); - tty_set_termios_ldisc(tty, tty->ldisc.num); - if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { - tty_ldisc_put(o_ldisc.num); - /* This driver is always present */ - tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); - tty_set_termios_ldisc(tty, N_TTY); - if (tty->ldisc.open) { - int r = tty->ldisc.open(tty); - - if (r < 0) - panic("Couldn't open N_TTY ldisc for " - "%s --- error %d.", - tty_name(tty, buf), r); - } - } - } - /* At this point we hold a reference to the new ldisc and a - a reference to the old ldisc. If we ended up flipping back - to the existing ldisc we have two references to it */ - - if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) - tty->driver->set_ldisc(tty); - - tty_ldisc_put(o_ldisc.num); - - /* - * Allow ldisc referencing to occur as soon as the driver - * ldisc callback completes. - */ - - tty_ldisc_enable(tty); - if (o_tty) - tty_ldisc_enable(o_tty); - - /* Restart it in case no characters kick it off. Safe if - already running */ - if (work) - schedule_delayed_work(&tty->buf.work, 1); - return retval; -} - -/* - * This routine returns a tty driver structure, given a device number - */ -static struct tty_driver *get_tty_driver(dev_t device, int *index) -{ - struct tty_driver *p; - - list_for_each_entry(p, &tty_drivers, tty_drivers) { - dev_t base = MKDEV(p->major, p->minor_start); - if (device < base || device >= base + p->num) - continue; - *index = device - base; - return p; - } - return NULL; -} - -/* - * If we try to write to, or set the state of, a terminal and we're - * not in the foreground, send a SIGTTOU. If the signal is blocked or - * ignored, go ahead and perform the operation. (POSIX 7.2) - */ -int tty_check_change(struct tty_struct * tty) -{ - if (current->signal->tty != tty) - return 0; - if (tty->pgrp <= 0) { - printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n"); - return 0; - } - if (process_group(current) == tty->pgrp) - return 0; - if (is_ignored(SIGTTOU)) - return 0; - if (is_orphaned_pgrp(process_group(current))) - return -EIO; - (void) kill_pg(process_group(current), SIGTTOU, 1); - return -ERESTARTSYS; -} - -EXPORT_SYMBOL(tty_check_change); - -static ssize_t hung_up_tty_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t hung_up_tty_write(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) -{ - return -EIO; -} - -/* No kernel lock held - none needed ;) */ -static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait) -{ - return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; -} - -static int hung_up_tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - return cmd == TIOCSPGRP ? -ENOTTY : -EIO; -} - -static struct file_operations tty_fops = { - .llseek = no_llseek, - .read = tty_read, - .write = tty_write, - .poll = tty_poll, - .ioctl = tty_ioctl, - .open = tty_open, - .release = tty_release, - .fasync = tty_fasync, -}; - -#ifdef CONFIG_UNIX98_PTYS -static struct file_operations ptmx_fops = { - .llseek = no_llseek, - .read = tty_read, - .write = tty_write, - .poll = tty_poll, - .ioctl = tty_ioctl, - .open = ptmx_open, - .release = tty_release, - .fasync = tty_fasync, -}; -#endif - -static struct file_operations console_fops = { - .llseek = no_llseek, - .read = tty_read, - .write = redirected_tty_write, - .poll = tty_poll, - .ioctl = tty_ioctl, - .open = tty_open, - .release = tty_release, - .fasync = tty_fasync, -}; - -static struct file_operations hung_up_tty_fops = { - .llseek = no_llseek, - .read = hung_up_tty_read, - .write = hung_up_tty_write, - .poll = hung_up_tty_poll, - .ioctl = hung_up_tty_ioctl, - .release = tty_release, -}; - -static DEFINE_SPINLOCK(redirect_lock); -static struct file *redirect; - -/** - * tty_wakeup - request more data - * @tty: terminal - * - * Internal and external helper for wakeups of tty. This function - * informs the line discipline if present that the driver is ready - * to receive more output data. - */ - -void tty_wakeup(struct tty_struct *tty) -{ - struct tty_ldisc *ld; - - if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { - ld = tty_ldisc_ref(tty); - if(ld) { - if(ld->write_wakeup) - ld->write_wakeup(tty); - tty_ldisc_deref(ld); - } - } - wake_up_interruptible(&tty->write_wait); -} - -EXPORT_SYMBOL_GPL(tty_wakeup); - -/** - * tty_ldisc_flush - flush line discipline queue - * @tty: tty - * - * Flush the line discipline queue (if any) for this tty. If there - * is no line discipline active this is a no-op. - */ - -void tty_ldisc_flush(struct tty_struct *tty) -{ - struct tty_ldisc *ld = tty_ldisc_ref(tty); - if(ld) { - if(ld->flush_buffer) - ld->flush_buffer(tty); - tty_ldisc_deref(ld); - } -} - -EXPORT_SYMBOL_GPL(tty_ldisc_flush); - -/* - * This can be called by the "eventd" kernel thread. That is process synchronous, - * but doesn't hold any locks, so we need to make sure we have the appropriate - * locks for what we're doing.. - */ -static void do_tty_hangup(void *data) -{ - struct tty_struct *tty = (struct tty_struct *) data; - struct file * cons_filp = NULL; - struct file *filp, *f = NULL; - struct task_struct *p; - struct tty_ldisc *ld; - int closecount = 0, n; - - if (!tty) - return; - - /* inuse_filps is protected by the single kernel lock */ - lock_kernel(); - - spin_lock(&redirect_lock); - if (redirect && redirect->private_data == tty) { - f = redirect; - redirect = NULL; - } - spin_unlock(&redirect_lock); - - check_tty_count(tty, "do_tty_hangup"); - file_list_lock(); - /* This breaks for file handles being sent over AF_UNIX sockets ? */ - list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { - if (filp->f_op->write == redirected_tty_write) - cons_filp = filp; - if (filp->f_op->write != tty_write) - continue; - closecount++; - tty_fasync(-1, filp, 0); /* can't block */ - filp->f_op = &hung_up_tty_fops; - } - file_list_unlock(); - - /* FIXME! What are the locking issues here? This may me overdoing things.. - * this question is especially important now that we've removed the irqlock. */ - - ld = tty_ldisc_ref(tty); - if(ld != NULL) /* We may have no line discipline at this point */ - { - if (ld->flush_buffer) - ld->flush_buffer(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - ld->write_wakeup) - ld->write_wakeup(tty); - if (ld->hangup) - ld->hangup(tty); - } - - /* FIXME: Once we trust the LDISC code better we can wait here for - ldisc completion and fix the driver call race */ - - wake_up_interruptible(&tty->write_wait); - wake_up_interruptible(&tty->read_wait); - - /* - * Shutdown the current line discipline, and reset it to - * N_TTY. - */ - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) - { - down(&tty->termios_sem); - *tty->termios = tty->driver->init_termios; - up(&tty->termios_sem); - } - - /* Defer ldisc switch */ - /* tty_deferred_ldisc_switch(N_TTY); - - This should get done automatically when the port closes and - tty_release is called */ - - read_lock(&tasklist_lock); - if (tty->session > 0) { - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - if (p->signal->tty == tty) - p->signal->tty = NULL; - if (!p->signal->leader) - continue; - send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p); - send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p); - if (tty->pgrp > 0) - p->signal->tty_old_pgrp = tty->pgrp; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); - } - read_unlock(&tasklist_lock); - - tty->flags = 0; - tty->session = 0; - tty->pgrp = -1; - tty->ctrl_status = 0; - /* - * If one of the devices matches a console pointer, we - * cannot just call hangup() because that will cause - * tty->count and state->count to go out of sync. - * So we just call close() the right number of times. - */ - if (cons_filp) { - if (tty->driver->close) - for (n = 0; n < closecount; n++) - tty->driver->close(tty, cons_filp); - } else if (tty->driver->hangup) - (tty->driver->hangup)(tty); - - /* We don't want to have driver/ldisc interactions beyond - the ones we did here. The driver layer expects no - calls after ->hangup() from the ldisc side. However we - can't yet guarantee all that */ - - set_bit(TTY_HUPPED, &tty->flags); - if (ld) { - tty_ldisc_enable(tty); - tty_ldisc_deref(ld); - } - unlock_kernel(); - if (f) - fput(f); -} - -void tty_hangup(struct tty_struct * tty) -{ -#ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); -#endif - schedule_work(&tty->hangup_work); -} - -EXPORT_SYMBOL(tty_hangup); - -void tty_vhangup(struct tty_struct * tty) -{ -#ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); -#endif - do_tty_hangup((void *) tty); -} -EXPORT_SYMBOL(tty_vhangup); - -int tty_hung_up_p(struct file * filp) -{ - return (filp->f_op == &hung_up_tty_fops); -} - -EXPORT_SYMBOL(tty_hung_up_p); - -/* - * This function is typically called only by the session leader, when - * it wants to disassociate itself from its controlling tty. - * - * It performs the following functions: - * (1) Sends a SIGHUP and SIGCONT to the foreground process group - * (2) Clears the tty from being controlling the session - * (3) Clears the controlling tty for all processes in the - * session group. - * - * The argument on_exit is set to 1 if called when a process is - * exiting; it is 0 if called by the ioctl TIOCNOTTY. - */ -void disassociate_ctty(int on_exit) -{ - struct tty_struct *tty; - struct task_struct *p; - int tty_pgrp = -1; - - lock_kernel(); - - down(&tty_sem); - tty = current->signal->tty; - if (tty) { - tty_pgrp = tty->pgrp; - up(&tty_sem); - if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) - tty_vhangup(tty); - } else { - if (current->signal->tty_old_pgrp) { - kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit); - kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit); - } - up(&tty_sem); - unlock_kernel(); - return; - } - if (tty_pgrp > 0) { - kill_pg(tty_pgrp, SIGHUP, on_exit); - if (!on_exit) - kill_pg(tty_pgrp, SIGCONT, on_exit); - } - - /* Must lock changes to tty_old_pgrp */ - down(&tty_sem); - current->signal->tty_old_pgrp = 0; - tty->session = 0; - tty->pgrp = -1; - - /* Now clear signal->tty under the lock */ - read_lock(&tasklist_lock); - do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); - read_unlock(&tasklist_lock); - up(&tty_sem); - unlock_kernel(); -} - -void stop_tty(struct tty_struct *tty) -{ - if (tty->stopped) - return; - tty->stopped = 1; - if (tty->link && tty->link->packet) { - tty->ctrl_status &= ~TIOCPKT_START; - tty->ctrl_status |= TIOCPKT_STOP; - wake_up_interruptible(&tty->link->read_wait); - } - if (tty->driver->stop) - (tty->driver->stop)(tty); -} - -EXPORT_SYMBOL(stop_tty); - -void start_tty(struct tty_struct *tty) -{ - if (!tty->stopped || tty->flow_stopped) - return; - tty->stopped = 0; - if (tty->link && tty->link->packet) { - tty->ctrl_status &= ~TIOCPKT_STOP; - tty->ctrl_status |= TIOCPKT_START; - wake_up_interruptible(&tty->link->read_wait); - } - if (tty->driver->start) - (tty->driver->start)(tty); - - /* If we have a running line discipline it may need kicking */ - tty_wakeup(tty); - wake_up_interruptible(&tty->write_wait); -} - -EXPORT_SYMBOL(start_tty); - -static ssize_t tty_read(struct file * file, char __user * buf, size_t count, - loff_t *ppos) -{ - int i; - struct tty_struct * tty; - struct inode *inode; - struct tty_ldisc *ld; - - tty = (struct tty_struct *)file->private_data; - inode = file->f_dentry->d_inode; - if (tty_paranoia_check(tty, inode, "tty_read")) - return -EIO; - if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) - return -EIO; - - /* We want to wait for the line discipline to sort out in this - situation */ - ld = tty_ldisc_ref_wait(tty); - lock_kernel(); - if (ld->read) - i = (ld->read)(tty,file,buf,count); - else - i = -EIO; - tty_ldisc_deref(ld); - unlock_kernel(); - if (i > 0) - inode->i_atime = current_fs_time(inode->i_sb); - return i; -} - -/* - * Split writes up in sane blocksizes to avoid - * denial-of-service type attacks - */ -static inline ssize_t do_tty_write( - ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t), - struct tty_struct *tty, - struct file *file, - const char __user *buf, - size_t count) -{ - ssize_t ret = 0, written = 0; - unsigned int chunk; - - if (down_interruptible(&tty->atomic_write)) { - return -ERESTARTSYS; - } - - /* - * We chunk up writes into a temporary buffer. This - * simplifies low-level drivers immensely, since they - * don't have locking issues and user mode accesses. - * - * But if TTY_NO_WRITE_SPLIT is set, we should use a - * big chunk-size.. - * - * The default chunk-size is 2kB, because the NTTY - * layer has problems with bigger chunks. It will - * claim to be able to handle more characters than - * it actually does. - */ - chunk = 2048; - if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) - chunk = 65536; - if (count < chunk) - chunk = count; - - /* write_buf/write_cnt is protected by the atomic_write semaphore */ - if (tty->write_cnt < chunk) { - unsigned char *buf; - - if (chunk < 1024) - chunk = 1024; - - buf = kmalloc(chunk, GFP_KERNEL); - if (!buf) { - up(&tty->atomic_write); - return -ENOMEM; - } - kfree(tty->write_buf); - tty->write_cnt = chunk; - tty->write_buf = buf; - } - - /* Do the write .. */ - for (;;) { - size_t size = count; - if (size > chunk) - size = chunk; - ret = -EFAULT; - if (copy_from_user(tty->write_buf, buf, size)) - break; - lock_kernel(); - ret = write(tty, file, tty->write_buf, size); - unlock_kernel(); - if (ret <= 0) - break; - written += ret; - buf += ret; - count -= ret; - if (!count) - break; - ret = -ERESTARTSYS; - if (signal_pending(current)) - break; - cond_resched(); - } - if (written) { - struct inode *inode = file->f_dentry->d_inode; - inode->i_mtime = current_fs_time(inode->i_sb); - ret = written; - } - up(&tty->atomic_write); - return ret; -} - - -static ssize_t tty_write(struct file * file, const char __user * buf, size_t count, - loff_t *ppos) -{ - struct tty_struct * tty; - struct inode *inode = file->f_dentry->d_inode; - ssize_t ret; - struct tty_ldisc *ld; - - tty = (struct tty_struct *)file->private_data; - if (tty_paranoia_check(tty, inode, "tty_write")) - return -EIO; - if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) - return -EIO; - - ld = tty_ldisc_ref_wait(tty); - if (!ld->write) - ret = -EIO; - else - ret = do_tty_write(ld->write, tty, file, buf, count); - tty_ldisc_deref(ld); - return ret; -} - -ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count, - loff_t *ppos) -{ - struct file *p = NULL; - - spin_lock(&redirect_lock); - if (redirect) { - get_file(redirect); - p = redirect; - } - spin_unlock(&redirect_lock); - - if (p) { - ssize_t res; - res = vfs_write(p, buf, count, &p->f_pos); - fput(p); - return res; - } - - return tty_write(file, buf, count, ppos); -} - -static char ptychar[] = "pqrstuvwxyzabcde"; - -static inline void pty_line_name(struct tty_driver *driver, int index, char *p) -{ - int i = index + driver->name_base; - /* ->name is initialized to "ttyp", but "tty" is expected */ - sprintf(p, "%s%c%x", - driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, - ptychar[i >> 4 & 0xf], i & 0xf); -} - -static inline void tty_line_name(struct tty_driver *driver, int index, char *p) -{ - sprintf(p, "%s%d", driver->name, index + driver->name_base); -} - -/* - * WSH 06/09/97: Rewritten to remove races and properly clean up after a - * failed open. The new code protects the open with a semaphore, so it's - * really quite straightforward. The semaphore locking can probably be - * relaxed for the (most common) case of reopening a tty. - */ -static int init_dev(struct tty_driver *driver, int idx, - struct tty_struct **ret_tty) -{ - struct tty_struct *tty, *o_tty; - struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; - struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; - int retval=0; - - /* check whether we're reopening an existing tty */ - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { - tty = devpts_get_tty(idx); - if (tty && driver->subtype == PTY_TYPE_MASTER) - tty = tty->link; - } else { - tty = driver->ttys[idx]; - } - if (tty) goto fast_track; - - /* - * First time open is complex, especially for PTY devices. - * This code guarantees that either everything succeeds and the - * TTY is ready for operation, or else the table slots are vacated - * and the allocated memory released. (Except that the termios - * and locked termios may be retained.) - */ - - if (!try_module_get(driver->owner)) { - retval = -ENODEV; - goto end_init; - } - - o_tty = NULL; - tp = o_tp = NULL; - ltp = o_ltp = NULL; - - tty = alloc_tty_struct(); - if(!tty) - goto fail_no_mem; - initialize_tty_struct(tty); - tty->driver = driver; - tty->index = idx; - tty_line_name(driver, idx, tty->name); - - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { - tp_loc = &tty->termios; - ltp_loc = &tty->termios_locked; - } else { - tp_loc = &driver->termios[idx]; - ltp_loc = &driver->termios_locked[idx]; - } - - if (!*tp_loc) { - tp = (struct termios *) kmalloc(sizeof(struct termios), - GFP_KERNEL); - if (!tp) - goto free_mem_out; - *tp = driver->init_termios; - } - - if (!*ltp_loc) { - ltp = (struct termios *) kmalloc(sizeof(struct termios), - GFP_KERNEL); - if (!ltp) - goto free_mem_out; - memset(ltp, 0, sizeof(struct termios)); - } - - if (driver->type == TTY_DRIVER_TYPE_PTY) { - o_tty = alloc_tty_struct(); - if (!o_tty) - goto free_mem_out; - initialize_tty_struct(o_tty); - o_tty->driver = driver->other; - o_tty->index = idx; - tty_line_name(driver->other, idx, o_tty->name); - - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { - o_tp_loc = &o_tty->termios; - o_ltp_loc = &o_tty->termios_locked; - } else { - o_tp_loc = &driver->other->termios[idx]; - o_ltp_loc = &driver->other->termios_locked[idx]; - } - - if (!*o_tp_loc) { - o_tp = (struct termios *) - kmalloc(sizeof(struct termios), GFP_KERNEL); - if (!o_tp) - goto free_mem_out; - *o_tp = driver->other->init_termios; - } - - if (!*o_ltp_loc) { - o_ltp = (struct termios *) - kmalloc(sizeof(struct termios), GFP_KERNEL); - if (!o_ltp) - goto free_mem_out; - memset(o_ltp, 0, sizeof(struct termios)); - } - - /* - * Everything allocated ... set up the o_tty structure. - */ - if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) { - driver->other->ttys[idx] = o_tty; - } - if (!*o_tp_loc) - *o_tp_loc = o_tp; - if (!*o_ltp_loc) - *o_ltp_loc = o_ltp; - o_tty->termios = *o_tp_loc; - o_tty->termios_locked = *o_ltp_loc; - driver->other->refcount++; - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; - - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; - } - - /* - * All structures have been allocated, so now we install them. - * Failures after this point use release_mem to clean up, so - * there's no need to null out the local pointers. - */ - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { - driver->ttys[idx] = tty; - } - - if (!*tp_loc) - *tp_loc = tp; - if (!*ltp_loc) - *ltp_loc = ltp; - tty->termios = *tp_loc; - tty->termios_locked = *ltp_loc; - driver->refcount++; - tty->count++; - - /* - * Structures all installed ... call the ldisc open routines. - * If we fail here just call release_mem to clean up. No need - * to decrement the use counts, as release_mem doesn't care. - */ - - if (tty->ldisc.open) { - retval = (tty->ldisc.open)(tty); - if (retval) - goto release_mem_out; - } - if (o_tty && o_tty->ldisc.open) { - retval = (o_tty->ldisc.open)(o_tty); - if (retval) { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - goto release_mem_out; - } - tty_ldisc_enable(o_tty); - } - tty_ldisc_enable(tty); - goto success; - - /* - * This fast open can be used if the tty is already open. - * No memory is allocated, and the only failures are from - * attempting to open a closing tty or attempting multiple - * opens on a pty master. - */ -fast_track: - if (test_bit(TTY_CLOSING, &tty->flags)) { - retval = -EIO; - goto end_init; - } - if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER) { - /* - * special case for PTY masters: only one open permitted, - * and the slave side open count is incremented as well. - */ - if (tty->count) { - retval = -EIO; - goto end_init; - } - tty->link->count++; - } - tty->count++; - tty->driver = driver; /* N.B. why do this every time?? */ - - /* FIXME */ - if(!test_bit(TTY_LDISC, &tty->flags)) - printk(KERN_ERR "init_dev but no ldisc\n"); -success: - *ret_tty = tty; - - /* All paths come through here to release the semaphore */ -end_init: - return retval; - - /* Release locally allocated memory ... nothing placed in slots */ -free_mem_out: - kfree(o_tp); - if (o_tty) - free_tty_struct(o_tty); - kfree(ltp); - kfree(tp); - free_tty_struct(tty); - -fail_no_mem: - module_put(driver->owner); - retval = -ENOMEM; - goto end_init; - - /* call the tty release_mem routine to clean out this slot */ -release_mem_out: - printk(KERN_INFO "init_dev: ldisc open failed, " - "clearing slot %d\n", idx); - release_mem(tty, idx); - goto end_init; -} - -/* - * Releases memory associated with a tty structure, and clears out the - * driver table slots. - */ -static void release_mem(struct tty_struct *tty, int idx) -{ - struct tty_struct *o_tty; - struct termios *tp; - int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; - - if ((o_tty = tty->link) != NULL) { - if (!devpts) - o_tty->driver->ttys[idx] = NULL; - if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - tp = o_tty->termios; - if (!devpts) - o_tty->driver->termios[idx] = NULL; - kfree(tp); - - tp = o_tty->termios_locked; - if (!devpts) - o_tty->driver->termios_locked[idx] = NULL; - kfree(tp); - } - o_tty->magic = 0; - o_tty->driver->refcount--; - file_list_lock(); - list_del_init(&o_tty->tty_files); - file_list_unlock(); - free_tty_struct(o_tty); - } - - if (!devpts) - tty->driver->ttys[idx] = NULL; - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - tp = tty->termios; - if (!devpts) - tty->driver->termios[idx] = NULL; - kfree(tp); - - tp = tty->termios_locked; - if (!devpts) - tty->driver->termios_locked[idx] = NULL; - kfree(tp); - } - - tty->magic = 0; - tty->driver->refcount--; - file_list_lock(); - list_del_init(&tty->tty_files); - file_list_unlock(); - module_put(tty->driver->owner); - free_tty_struct(tty); -} - -/* - * Even releasing the tty structures is a tricky business.. We have - * to be very careful that the structures are all released at the - * same time, as interrupts might otherwise get the wrong pointers. - * - * WSH 09/09/97: rewritten to avoid some nasty race conditions that could - * lead to double frees or releasing memory still in use. - */ -static void release_dev(struct file * filp) -{ - struct tty_struct *tty, *o_tty; - int pty_master, tty_closing, o_tty_closing, do_sleep; - int devpts_master, devpts; - int idx; - char buf[64]; - unsigned long flags; - - tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev")) - return; - - check_tty_count(tty, "release_dev"); - - tty_fasync(-1, filp, 0); - - idx = tty->index; - pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER); - devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; - devpts_master = pty_master && devpts; - o_tty = tty->link; - -#ifdef TTY_PARANOIA_CHECK - if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "release_dev: bad idx when trying to " - "free (%s)\n", tty->name); - return; - } - if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { - if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " - "for (%s)\n", idx, tty->name); - return; - } - if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " - "for (%s)\n", - idx, tty->name); - return; - } - if (tty->termios_locked != tty->driver->termios_locked[idx]) { - printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " - "termios_locked for (%s)\n", - idx, tty->name); - return; - } - } -#endif - -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", - tty_name(tty, buf), tty->count); -#endif - -#ifdef TTY_PARANOIA_CHECK - if (tty->driver->other && - !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { - if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "release_dev: other->table[%d] " - "not o_tty for (%s)\n", - idx, tty->name); - return; - } - if (o_tty->termios != tty->driver->other->termios[idx]) { - printk(KERN_DEBUG "release_dev: other->termios[%d] " - "not o_termios for (%s)\n", - idx, tty->name); - return; - } - if (o_tty->termios_locked != - tty->driver->other->termios_locked[idx]) { - printk(KERN_DEBUG "release_dev: other->termios_locked[" - "%d] not o_termios_locked for (%s)\n", - idx, tty->name); - return; - } - if (o_tty->link != tty) { - printk(KERN_DEBUG "release_dev: bad pty pointers\n"); - return; - } - } -#endif - if (tty->driver->close) - tty->driver->close(tty, filp); - - /* - * Sanity check: if tty->count is going to zero, there shouldn't be - * any waiters on tty->read_wait or tty->write_wait. We test the - * wait queues and kick everyone out _before_ actually starting to - * close. This ensures that we won't block while releasing the tty - * structure. - * - * The test for the o_tty closing is necessary, since the master and - * slave sides may close in any order. If the slave side closes out - * first, its count will be one, since the master side holds an open. - * Thus this test wouldn't be triggered at the time the slave closes, - * so we do it now. - * - * Note that it's possible for the tty to be opened again while we're - * flushing out waiters. By recalculating the closing flags before - * each iteration we avoid any problems. - */ - while (1) { - /* Guard against races with tty->count changes elsewhere and - opens on /dev/tty */ - - down(&tty_sem); - tty_closing = tty->count <= 1; - o_tty_closing = o_tty && - (o_tty->count <= (pty_master ? 1 : 0)); - do_sleep = 0; - - if (tty_closing) { - if (waitqueue_active(&tty->read_wait)) { - wake_up(&tty->read_wait); - do_sleep++; - } - if (waitqueue_active(&tty->write_wait)) { - wake_up(&tty->write_wait); - do_sleep++; - } - } - if (o_tty_closing) { - if (waitqueue_active(&o_tty->read_wait)) { - wake_up(&o_tty->read_wait); - do_sleep++; - } - if (waitqueue_active(&o_tty->write_wait)) { - wake_up(&o_tty->write_wait); - do_sleep++; - } - } - if (!do_sleep) - break; - - printk(KERN_WARNING "release_dev: %s: read/write wait queue " - "active!\n", tty_name(tty, buf)); - up(&tty_sem); - schedule(); - } - - /* - * The closing flags are now consistent with the open counts on - * both sides, and we've completed the last operation that could - * block, so it's safe to proceed with closing. - */ - if (pty_master) { - if (--o_tty->count < 0) { - printk(KERN_WARNING "release_dev: bad pty slave count " - "(%d) for %s\n", - o_tty->count, tty_name(o_tty, buf)); - o_tty->count = 0; - } - } - if (--tty->count < 0) { - printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", - tty->count, tty_name(tty, buf)); - tty->count = 0; - } - - /* - * We've decremented tty->count, so we need to remove this file - * descriptor off the tty->tty_files list; this serves two - * purposes: - * - check_tty_count sees the correct number of file descriptors - * associated with this tty. - * - do_tty_hangup no longer sees this file descriptor as - * something that needs to be handled for hangups. - */ - file_kill(filp); - filp->private_data = NULL; - - /* - * Perform some housekeeping before deciding whether to return. - * - * Set the TTY_CLOSING flag if this was the last open. In the - * case of a pty we may have to wait around for the other side - * to close, and TTY_CLOSING makes sure we can't be reopened. - */ - if(tty_closing) - set_bit(TTY_CLOSING, &tty->flags); - if(o_tty_closing) - set_bit(TTY_CLOSING, &o_tty->flags); - - /* - * If _either_ side is closing, make sure there aren't any - * processes that still think tty or o_tty is their controlling - * tty. - */ - if (tty_closing || o_tty_closing) { - struct task_struct *p; - - read_lock(&tasklist_lock); - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); - if (o_tty) - do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); - read_unlock(&tasklist_lock); - } - - up(&tty_sem); - - /* check whether both sides are closing ... */ - if (!tty_closing || (o_tty && !o_tty_closing)) - return; - -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "freeing tty structure..."); -#endif - /* - * Prevent flush_to_ldisc() from rescheduling the work for later. Then - * kill any delayed work. As this is the final close it does not - * race with the set_ldisc code path. - */ - clear_bit(TTY_LDISC, &tty->flags); - clear_bit(TTY_DONT_FLIP, &tty->flags); - cancel_delayed_work(&tty->buf.work); - - /* - * Wait for ->hangup_work and ->buf.work handlers to terminate - */ - - flush_scheduled_work(); - - /* - * Wait for any short term users (we know they are just driver - * side waiters as the file is closing so user count on the file - * side is zero. - */ - spin_lock_irqsave(&tty_ldisc_lock, flags); - while(tty->ldisc.refcount) - { - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); - spin_lock_irqsave(&tty_ldisc_lock, flags); - } - spin_unlock_irqrestore(&tty_ldisc_lock, flags); - /* - * Shutdown the current line discipline, and reset it to N_TTY. - * N.B. why reset ldisc when we're releasing the memory?? - * - * FIXME: this MUST get fixed for the new reflocking - */ - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty_ldisc_put(tty->ldisc.num); - - /* - * Switch the line discipline back - */ - tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); - tty_set_termios_ldisc(tty,N_TTY); - if (o_tty) { - /* FIXME: could o_tty be in setldisc here ? */ - clear_bit(TTY_LDISC, &o_tty->flags); - if (o_tty->ldisc.close) - (o_tty->ldisc.close)(o_tty); - tty_ldisc_put(o_tty->ldisc.num); - tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); - tty_set_termios_ldisc(o_tty,N_TTY); - } - /* - * The release_mem function takes care of the details of clearing - * the slots and preserving the termios structure. - */ - release_mem(tty, idx); - -#ifdef CONFIG_UNIX98_PTYS - /* Make this pty number available for reallocation */ - if (devpts) { - down(&allocated_ptys_lock); - idr_remove(&allocated_ptys, idx); - up(&allocated_ptys_lock); - } -#endif - -} - -/* - * tty_open and tty_release keep up the tty count that contains the - * number of opens done on a tty. We cannot use the inode-count, as - * different inodes might point to the same tty. - * - * Open-counting is needed for pty masters, as well as for keeping - * track of serial lines: DTR is dropped when the last close happens. - * (This is not done solely through tty->count, now. - Ted 1/27/92) - * - * The termios state of a pty is reset on first open so that - * settings don't persist across reuse. - */ -static int tty_open(struct inode * inode, struct file * filp) -{ - struct tty_struct *tty; - int noctty, retval; - struct tty_driver *driver; - int index; - dev_t device = inode->i_rdev; - unsigned short saved_flags = filp->f_flags; - - nonseekable_open(inode, filp); - -retry_open: - noctty = filp->f_flags & O_NOCTTY; - index = -1; - retval = 0; - - down(&tty_sem); - - if (device == MKDEV(TTYAUX_MAJOR,0)) { - if (!current->signal->tty) { - up(&tty_sem); - return -ENXIO; - } - driver = current->signal->tty->driver; - index = current->signal->tty->index; - filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ - /* noctty = 1; */ - goto got_driver; - } -#ifdef CONFIG_VT - if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) { - extern struct tty_driver *console_driver; - driver = console_driver; - index = fg_console; - noctty = 1; - goto got_driver; - } -#endif - if (device == MKDEV(TTYAUX_MAJOR,1)) { - driver = console_device(&index); - if (driver) { - /* Don't let /dev/console block */ - filp->f_flags |= O_NONBLOCK; - noctty = 1; - goto got_driver; - } - up(&tty_sem); - return -ENODEV; - } - - driver = get_tty_driver(device, &index); - if (!driver) { - up(&tty_sem); - return -ENODEV; - } -got_driver: - retval = init_dev(driver, index, &tty); - up(&tty_sem); - if (retval) - return retval; - - filp->private_data = tty; - file_move(filp, &tty->tty_files); - check_tty_count(tty, "tty_open"); - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - noctty = 1; -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "opening %s...", tty->name); -#endif - if (!retval) { - if (tty->driver->open) - retval = tty->driver->open(tty, filp); - else - retval = -ENODEV; - } - filp->f_flags = saved_flags; - - if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) - retval = -EBUSY; - - if (retval) { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "error %d in opening %s...", retval, - tty->name); -#endif - release_dev(filp); - if (retval != -ERESTARTSYS) - return retval; - if (signal_pending(current)) - return retval; - schedule(); - /* - * Need to reset f_op in case a hangup happened. - */ - if (filp->f_op == &hung_up_tty_fops) - filp->f_op = &tty_fops; - goto retry_open; - } - if (!noctty && - current->signal->leader && - !current->signal->tty && - tty->session == 0) { - task_lock(current); - current->signal->tty = tty; - task_unlock(current); - current->signal->tty_old_pgrp = 0; - tty->session = current->signal->session; - tty->pgrp = process_group(current); - } - return 0; -} - -#ifdef CONFIG_UNIX98_PTYS -static int ptmx_open(struct inode * inode, struct file * filp) -{ - struct tty_struct *tty; - int retval; - int index; - int idr_ret; - - nonseekable_open(inode, filp); - - /* find a device that is not in use. */ - down(&allocated_ptys_lock); - if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { - up(&allocated_ptys_lock); - return -ENOMEM; - } - idr_ret = idr_get_new(&allocated_ptys, NULL, &index); - if (idr_ret < 0) { - up(&allocated_ptys_lock); - if (idr_ret == -EAGAIN) - return -ENOMEM; - return -EIO; - } - if (index >= pty_limit) { - idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); - return -EIO; - } - up(&allocated_ptys_lock); - - down(&tty_sem); - retval = init_dev(ptm_driver, index, &tty); - up(&tty_sem); - - if (retval) - goto out; - - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - filp->private_data = tty; - file_move(filp, &tty->tty_files); - - retval = -ENOMEM; - if (devpts_pty_new(tty->link)) - goto out1; - - check_tty_count(tty, "tty_open"); - retval = ptm_driver->open(tty, filp); - if (!retval) - return 0; -out1: - release_dev(filp); -out: - down(&allocated_ptys_lock); - idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); - return retval; -} -#endif - -static int tty_release(struct inode * inode, struct file * filp) -{ - lock_kernel(); - release_dev(filp); - unlock_kernel(); - return 0; -} - -/* No kernel lock held - fine */ -static unsigned int tty_poll(struct file * filp, poll_table * wait) -{ - struct tty_struct * tty; - struct tty_ldisc *ld; - int ret = 0; - - tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll")) - return 0; - - ld = tty_ldisc_ref_wait(tty); - if (ld->poll) - ret = (ld->poll)(tty, filp, wait); - tty_ldisc_deref(ld); - return ret; -} - -static int tty_fasync(int fd, struct file * filp, int on) -{ - struct tty_struct * tty; - int retval; - - tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_fasync")) - return 0; - - retval = fasync_helper(fd, filp, on, &tty->fasync); - if (retval <= 0) - return retval; - - if (on) { - if (!waitqueue_active(&tty->read_wait)) - tty->minimum_to_wake = 1; - retval = f_setown(filp, (-tty->pgrp) ? : current->pid, 0); - if (retval) - return retval; - } else { - if (!tty->fasync && !waitqueue_active(&tty->read_wait)) - tty->minimum_to_wake = N_TTY_BUF_SIZE; - } - return 0; -} - -static int tiocsti(struct tty_struct *tty, char __user *p) -{ - char ch, mbz = 0; - struct tty_ldisc *ld; - - if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ch, p)) - return -EFAULT; - ld = tty_ldisc_ref_wait(tty); - ld->receive_buf(tty, &ch, &mbz, 1); - tty_ldisc_deref(ld); - return 0; -} - -static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) -{ - if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) - return -EFAULT; - return 0; -} - -static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, - struct winsize __user * arg) -{ - struct winsize tmp_ws; - - if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) - return -EFAULT; - if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) - return 0; -#ifdef CONFIG_VT - if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { - int rc; - - acquire_console_sem(); - rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row); - release_console_sem(); - if (rc) - return -ENXIO; - } -#endif - if (tty->pgrp > 0) - kill_pg(tty->pgrp, SIGWINCH, 1); - if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0)) - kill_pg(real_tty->pgrp, SIGWINCH, 1); - tty->winsize = tmp_ws; - real_tty->winsize = tmp_ws; - return 0; -} - -static int tioccons(struct file *file) -{ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (file->f_op->write == redirected_tty_write) { - struct file *f; - spin_lock(&redirect_lock); - f = redirect; - redirect = NULL; - spin_unlock(&redirect_lock); - if (f) - fput(f); - return 0; - } - spin_lock(&redirect_lock); - if (redirect) { - spin_unlock(&redirect_lock); - return -EBUSY; - } - get_file(file); - redirect = file; - spin_unlock(&redirect_lock); - return 0; -} - - -static int fionbio(struct file *file, int __user *p) -{ - int nonblock; - - if (get_user(nonblock, p)) - return -EFAULT; - - if (nonblock) - file->f_flags |= O_NONBLOCK; - else - file->f_flags &= ~O_NONBLOCK; - return 0; -} - -static int tiocsctty(struct tty_struct *tty, int arg) -{ - task_t *p; - - if (current->signal->leader && - (current->signal->session == tty->session)) - return 0; - /* - * The process must be a session leader and - * not have a controlling tty already. - */ - if (!current->signal->leader || current->signal->tty) - return -EPERM; - if (tty->session > 0) { - /* - * This tty is already the controlling - * tty for another session group! - */ - if ((arg == 1) && capable(CAP_SYS_ADMIN)) { - /* - * Steal it away - */ - - read_lock(&tasklist_lock); - do_each_task_pid(tty->session, PIDTYPE_SID, p) { - p->signal->tty = NULL; - } while_each_task_pid(tty->session, PIDTYPE_SID, p); - read_unlock(&tasklist_lock); - } else - return -EPERM; - } - task_lock(current); - current->signal->tty = tty; - task_unlock(current); - current->signal->tty_old_pgrp = 0; - tty->session = current->signal->session; - tty->pgrp = process_group(current); - return 0; -} - -static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) -{ - /* - * (tty == real_tty) is a cheap way of - * testing if the tty is NOT a master pty. - */ - if (tty == real_tty && current->signal->tty != real_tty) - return -ENOTTY; - return put_user(real_tty->pgrp, p); -} - -static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) -{ - pid_t pgrp; - int retval = tty_check_change(real_tty); - - if (retval == -EIO) - return -ENOTTY; - if (retval) - return retval; - if (!current->signal->tty || - (current->signal->tty != real_tty) || - (real_tty->session != current->signal->session)) - return -ENOTTY; - if (get_user(pgrp, p)) - return -EFAULT; - if (pgrp < 0) - return -EINVAL; - if (session_of_pgrp(pgrp) != current->signal->session) - return -EPERM; - real_tty->pgrp = pgrp; - return 0; -} - -static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) -{ - /* - * (tty == real_tty) is a cheap way of - * testing if the tty is NOT a master pty. - */ - if (tty == real_tty && current->signal->tty != real_tty) - return -ENOTTY; - if (real_tty->session <= 0) - return -ENOTTY; - return put_user(real_tty->session, p); -} - -static int tiocsetd(struct tty_struct *tty, int __user *p) -{ - int ldisc; - - if (get_user(ldisc, p)) - return -EFAULT; - return tty_set_ldisc(tty, ldisc); -} - -static int send_break(struct tty_struct *tty, unsigned int duration) -{ - tty->driver->break_ctl(tty, -1); - if (!signal_pending(current)) { - msleep_interruptible(duration); - } - tty->driver->break_ctl(tty, 0); - if (signal_pending(current)) - return -EINTR; - return 0; -} - -static int -tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) -{ - int retval = -EINVAL; - - if (tty->driver->tiocmget) { - retval = tty->driver->tiocmget(tty, file); - - if (retval >= 0) - retval = put_user(retval, p); - } - return retval; -} - -static int -tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, - unsigned __user *p) -{ - int retval = -EINVAL; - - if (tty->driver->tiocmset) { - unsigned int set, clear, val; - - retval = get_user(val, p); - if (retval) - return retval; - - set = clear = 0; - switch (cmd) { - case TIOCMBIS: - set = val; - break; - case TIOCMBIC: - clear = val; - break; - case TIOCMSET: - set = val; - clear = ~val; - break; - } - - set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; - clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; - - retval = tty->driver->tiocmset(tty, file, set, clear); - } - return retval; -} - -/* - * Split this up, as gcc can choke on it otherwise.. - */ -int tty_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct tty_struct *tty, *real_tty; - void __user *p = (void __user *)arg; - int retval; - struct tty_ldisc *ld; - - tty = (struct tty_struct *)file->private_data; - if (tty_paranoia_check(tty, inode, "tty_ioctl")) - return -EINVAL; - - real_tty = tty; - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - real_tty = tty->link; - - /* - * Break handling by driver - */ - if (!tty->driver->break_ctl) { - switch(cmd) { - case TIOCSBRK: - case TIOCCBRK: - if (tty->driver->ioctl) - return tty->driver->ioctl(tty, file, cmd, arg); - return -EINVAL; - - /* These two ioctl's always return success; even if */ - /* the driver doesn't support them. */ - case TCSBRK: - case TCSBRKP: - if (!tty->driver->ioctl) - return 0; - retval = tty->driver->ioctl(tty, file, cmd, arg); - if (retval == -ENOIOCTLCMD) - retval = 0; - return retval; - } - } - - /* - * Factor out some common prep work - */ - switch (cmd) { - case TIOCSETD: - case TIOCSBRK: - case TIOCCBRK: - case TCSBRK: - case TCSBRKP: - retval = tty_check_change(tty); - if (retval) - return retval; - if (cmd != TIOCCBRK) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - } - break; - } - - switch (cmd) { - case TIOCSTI: - return tiocsti(tty, p); - case TIOCGWINSZ: - return tiocgwinsz(tty, p); - case TIOCSWINSZ: - return tiocswinsz(tty, real_tty, p); - case TIOCCONS: - return real_tty!=tty ? -EINVAL : tioccons(file); - case FIONBIO: - return fionbio(file, p); - case TIOCEXCL: - set_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCNXCL: - clear_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCNOTTY: - if (current->signal->tty != tty) - return -ENOTTY; - if (current->signal->leader) - disassociate_ctty(0); - task_lock(current); - current->signal->tty = NULL; - task_unlock(current); - return 0; - case TIOCSCTTY: - return tiocsctty(tty, arg); - case TIOCGPGRP: - return tiocgpgrp(tty, real_tty, p); - case TIOCSPGRP: - return tiocspgrp(tty, real_tty, p); - case TIOCGSID: - return tiocgsid(tty, real_tty, p); - case TIOCGETD: - /* FIXME: check this is ok */ - return put_user(tty->ldisc.num, (int __user *)p); - case TIOCSETD: - return tiocsetd(tty, p); -#ifdef CONFIG_VT - case TIOCLINUX: - return tioclinux(tty, arg); -#endif - /* - * Break handling - */ - case TIOCSBRK: /* Turn break on, unconditionally */ - tty->driver->break_ctl(tty, -1); - return 0; - - case TIOCCBRK: /* Turn break off, unconditionally */ - tty->driver->break_ctl(tty, 0); - return 0; - case TCSBRK: /* SVID version: non-zero arg --> no break */ - /* - * XXX is the above comment correct, or the - * code below correct? Is this ioctl used at - * all by anyone? - */ - if (!arg) - return send_break(tty, 250); - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*100 : 250); - - case TIOCMGET: - return tty_tiocmget(tty, file, p); - - case TIOCMSET: - case TIOCMBIC: - case TIOCMBIS: - return tty_tiocmset(tty, file, cmd, p); - } - if (tty->driver->ioctl) { - retval = (tty->driver->ioctl)(tty, file, cmd, arg); - if (retval != -ENOIOCTLCMD) - return retval; - } - ld = tty_ldisc_ref_wait(tty); - retval = -EINVAL; - if (ld->ioctl) { - retval = ld->ioctl(tty, file, cmd, arg); - if (retval == -ENOIOCTLCMD) - retval = -EINVAL; - } - tty_ldisc_deref(ld); - return retval; -} - - -/* - * This implements the "Secure Attention Key" --- the idea is to - * prevent trojan horses by killing all processes associated with this - * tty when the user hits the "Secure Attention Key". Required for - * super-paranoid applications --- see the Orange Book for more details. - * - * This code could be nicer; ideally it should send a HUP, wait a few - * seconds, then send a INT, and then a KILL signal. But you then - * have to coordinate with the init process, since all processes associated - * with the current tty must be dead before the new getty is allowed - * to spawn. - * - * Now, if it would be correct ;-/ The current code has a nasty hole - - * it doesn't catch files in flight. We may send the descriptor to ourselves - * via AF_UNIX socket, close it and later fetch from socket. FIXME. - * - * Nasty bug: do_SAK is being called in interrupt context. This can - * deadlock. We punt it up to process context. AKPM - 16Mar2001 - */ -static void __do_SAK(void *arg) -{ -#ifdef TTY_SOFT_SAK - tty_hangup(tty); -#else - struct tty_struct *tty = arg; - struct task_struct *p; - int session; - int i; - struct file *filp; - struct tty_ldisc *disc; - struct fdtable *fdt; - - if (!tty) - return; - session = tty->session; - - /* We don't want an ldisc switch during this */ - disc = tty_ldisc_ref(tty); - if (disc && disc->flush_buffer) - disc->flush_buffer(tty); - tty_ldisc_deref(disc); - - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - - read_lock(&tasklist_lock); - do_each_task_pid(session, PIDTYPE_SID, p) { - if (p->signal->tty == tty || session > 0) { - printk(KERN_NOTICE "SAK: killed process %d" - " (%s): p->signal->session==tty->session\n", - p->pid, p->comm); - send_sig(SIGKILL, p, 1); - continue; - } - task_lock(p); - if (p->files) { - /* - * We don't take a ref to the file, so we must - * hold ->file_lock instead. - */ - spin_lock(&p->files->file_lock); - fdt = files_fdtable(p->files); - for (i=0; i < fdt->max_fds; i++) { - filp = fcheck_files(p->files, i); - if (!filp) - continue; - if (filp->f_op->read == tty_read && - filp->private_data == tty) { - printk(KERN_NOTICE "SAK: killed process %d" - " (%s): fd#%d opened to the tty\n", - p->pid, p->comm, i); - send_sig(SIGKILL, p, 1); - break; - } - } - spin_unlock(&p->files->file_lock); - } - task_unlock(p); - } while_each_task_pid(session, PIDTYPE_SID, p); - read_unlock(&tasklist_lock); -#endif -} - -/* - * The tq handling here is a little racy - tty->SAK_work may already be queued. - * Fortunately we don't need to worry, because if ->SAK_work is already queued, - * the values which we write to it will be identical to the values which it - * already has. --akpm - */ -void do_SAK(struct tty_struct *tty) -{ - if (!tty) - return; - PREPARE_WORK(&tty->SAK_work, __do_SAK, tty); - schedule_work(&tty->SAK_work); -} - -EXPORT_SYMBOL(do_SAK); - -/* - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. - */ - -static void flush_to_ldisc(void *private_) -{ - struct tty_struct *tty = (struct tty_struct *) private_; - unsigned long flags; - struct tty_ldisc *disc; - struct tty_buffer *tbuf, *head; - int count; - char *char_buf; - unsigned char *flag_buf; - - disc = tty_ldisc_ref(tty); - if (disc == NULL) /* !TTY_LDISC */ - return; - - if (test_bit(TTY_DONT_FLIP, &tty->flags)) { - /* - * Do it after the next timer tick: - */ - schedule_delayed_work(&tty->buf.work, 1); - goto out; - } - spin_lock_irqsave(&tty->buf.lock, flags); - head = tty->buf.head; - tty->buf.head = NULL; - while((tbuf = head) != NULL) { - while ((count = tbuf->commit - tbuf->read) != 0) { - char_buf = tbuf->char_buf_ptr + tbuf->read; - flag_buf = tbuf->flag_buf_ptr + tbuf->read; - tbuf->read += count; - spin_unlock_irqrestore(&tty->buf.lock, flags); - disc->receive_buf(tty, char_buf, flag_buf, count); - spin_lock_irqsave(&tty->buf.lock, flags); - } - if (tbuf->active) { - tty->buf.head = head; - break; - } - head = tbuf->next; - if (head == NULL) - tty->buf.tail = NULL; - tty_buffer_free(tty, tbuf); - } - spin_unlock_irqrestore(&tty->buf.lock, flags); -out: - tty_ldisc_deref(disc); -} - -/* - * Routine which returns the baud rate of the tty - * - * Note that the baud_table needs to be kept in sync with the - * include/asm/termbits.h file. - */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, -#ifdef __sparc__ - 76800, 153600, 307200, 614400, 921600 -#else - 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 -#endif -}; - -static int n_baud_table = ARRAY_SIZE(baud_table); - -/** - * tty_termios_baud_rate - * @termios: termios structure - * - * Convert termios baud rate data into a speed. This should be called - * with the termios lock held if this termios is a terminal termios - * structure. May change the termios data. - */ - -int tty_termios_baud_rate(struct termios *termios) -{ - unsigned int cbaud; - - cbaud = termios->c_cflag & CBAUD; - - if (cbaud & CBAUDEX) { - cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~CBAUDEX; - else - cbaud += 15; - } - return baud_table[cbaud]; -} - -EXPORT_SYMBOL(tty_termios_baud_rate); - -/** - * tty_get_baud_rate - get tty bit rates - * @tty: tty to query - * - * Returns the baud rate as an integer for this terminal. The - * termios lock must be held by the caller and the terminal bit - * flags may be updated. - */ - -int tty_get_baud_rate(struct tty_struct *tty) -{ - int baud = tty_termios_baud_rate(tty->termios); - - if (baud == 38400 && tty->alt_speed) { - if (!tty->warned) { - printk(KERN_WARNING "Use of setserial/setrocket to " - "set SPD_* flags is deprecated\n"); - tty->warned = 1; - } - baud = tty->alt_speed; - } - - return baud; -} - -EXPORT_SYMBOL(tty_get_baud_rate); - -/** - * tty_flip_buffer_push - terminal - * @tty: tty to push - * - * Queue a push of the terminal flip buffers to the line discipline. This - * function must not be called from IRQ context if tty->low_latency is set. - * - * In the event of the queue being busy for flipping the work will be - * held off and retried later. - */ - -void tty_flip_buffer_push(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) { - tty->buf.tail->active = 0; - tty->buf.tail->commit = tty->buf.tail->used; - } - spin_unlock_irqrestore(&tty->buf.lock, flags); - - if (tty->low_latency) - flush_to_ldisc((void *) tty); - else - schedule_delayed_work(&tty->buf.work, 1); -} - -EXPORT_SYMBOL(tty_flip_buffer_push); - - -/* - * This subroutine initializes a tty structure. - */ -static void initialize_tty_struct(struct tty_struct *tty) -{ - memset(tty, 0, sizeof(struct tty_struct)); - tty->magic = TTY_MAGIC; - tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); - tty->pgrp = -1; - tty->overrun_time = jiffies; - tty->buf.head = tty->buf.tail = NULL; - tty_buffer_init(tty); - INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); - init_MUTEX(&tty->buf.pty_sem); - init_MUTEX(&tty->termios_sem); - init_waitqueue_head(&tty->write_wait); - init_waitqueue_head(&tty->read_wait); - INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); - sema_init(&tty->atomic_read, 1); - sema_init(&tty->atomic_write, 1); - spin_lock_init(&tty->read_lock); - INIT_LIST_HEAD(&tty->tty_files); - INIT_WORK(&tty->SAK_work, NULL, NULL); -} - -/* - * The default put_char routine if the driver did not define one. - */ -static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) -{ - tty->driver->write(tty, &ch, 1); -} - -static struct class *tty_class; - -/** - * tty_register_device - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device for this - * tty device it can be set to NULL safely. - * - * This call is required to be made to register an individual tty device if - * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that - * bit is not set, this function should not be called. - */ -void tty_register_device(struct tty_driver *driver, unsigned index, - struct device *device) -{ - char name[64]; - dev_t dev = MKDEV(driver->major, driver->minor_start) + index; - - if (index >= driver->num) { - printk(KERN_ERR "Attempt to register invalid tty line number " - " (%d).\n", index); - return; - } - - devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, - "%s%d", driver->devfs_name, index + driver->name_base); - - if (driver->type == TTY_DRIVER_TYPE_PTY) - pty_line_name(driver, index, name); - else - tty_line_name(driver, index, name); - class_device_create(tty_class, NULL, dev, device, "%s", name); -} - -/** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * - * If a tty device is registered with a call to tty_register_device() then - * this function must be made when the tty device is gone. - */ -void tty_unregister_device(struct tty_driver *driver, unsigned index) -{ - devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); - class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); -} - -EXPORT_SYMBOL(tty_register_device); -EXPORT_SYMBOL(tty_unregister_device); - -struct tty_driver *alloc_tty_driver(int lines) -{ - struct tty_driver *driver; - - driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL); - if (driver) { - memset(driver, 0, sizeof(struct tty_driver)); - driver->magic = TTY_DRIVER_MAGIC; - driver->num = lines; - /* later we'll move allocation of tables here */ - } - return driver; -} - -void put_tty_driver(struct tty_driver *driver) -{ - kfree(driver); -} - -void tty_set_operations(struct tty_driver *driver, struct tty_operations *op) -{ - driver->open = op->open; - driver->close = op->close; - driver->write = op->write; - driver->put_char = op->put_char; - driver->flush_chars = op->flush_chars; - driver->write_room = op->write_room; - driver->chars_in_buffer = op->chars_in_buffer; - driver->ioctl = op->ioctl; - driver->set_termios = op->set_termios; - driver->throttle = op->throttle; - driver->unthrottle = op->unthrottle; - driver->stop = op->stop; - driver->start = op->start; - driver->hangup = op->hangup; - driver->break_ctl = op->break_ctl; - driver->flush_buffer = op->flush_buffer; - driver->set_ldisc = op->set_ldisc; - driver->wait_until_sent = op->wait_until_sent; - driver->send_xchar = op->send_xchar; - driver->read_proc = op->read_proc; - driver->write_proc = op->write_proc; - driver->tiocmget = op->tiocmget; - driver->tiocmset = op->tiocmset; -} - - -EXPORT_SYMBOL(alloc_tty_driver); -EXPORT_SYMBOL(put_tty_driver); -EXPORT_SYMBOL(tty_set_operations); - -/* - * Called by a tty driver to register itself. - */ -int tty_register_driver(struct tty_driver *driver) -{ - int error; - int i; - dev_t dev; - void **p = NULL; - - if (driver->flags & TTY_DRIVER_INSTALLED) - return 0; - - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { - p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); - if (!p) - return -ENOMEM; - memset(p, 0, driver->num * 3 * sizeof(void *)); - } - - if (!driver->major) { - error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, - (char*)driver->name); - if (!error) { - driver->major = MAJOR(dev); - driver->minor_start = MINOR(dev); - } - } else { - dev = MKDEV(driver->major, driver->minor_start); - error = register_chrdev_region(dev, driver->num, - (char*)driver->name); - } - if (error < 0) { - kfree(p); - return error; - } - - if (p) { - driver->ttys = (struct tty_struct **)p; - driver->termios = (struct termios **)(p + driver->num); - driver->termios_locked = (struct termios **)(p + driver->num * 2); - } else { - driver->ttys = NULL; - driver->termios = NULL; - driver->termios_locked = NULL; - } - - cdev_init(&driver->cdev, &tty_fops); - driver->cdev.owner = driver->owner; - error = cdev_add(&driver->cdev, dev, driver->num); - if (error) { - cdev_del(&driver->cdev); - unregister_chrdev_region(dev, driver->num); - driver->ttys = NULL; - driver->termios = driver->termios_locked = NULL; - kfree(p); - return error; - } - - if (!driver->put_char) - driver->put_char = tty_default_put_char; - - list_add(&driver->tty_drivers, &tty_drivers); - - if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { - for(i = 0; i < driver->num; i++) - tty_register_device(driver, i, NULL); - } - proc_tty_register_driver(driver); - return 0; -} - -EXPORT_SYMBOL(tty_register_driver); - -/* - * Called by a tty driver to unregister itself. - */ -int tty_unregister_driver(struct tty_driver *driver) -{ - int i; - struct termios *tp; - void *p; - - if (driver->refcount) - return -EBUSY; - - unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), - driver->num); - - list_del(&driver->tty_drivers); - - /* - * Free the termios and termios_locked structures because - * we don't want to get memory leaks when modular tty - * drivers are removed from the kernel. - */ - for (i = 0; i < driver->num; i++) { - tp = driver->termios[i]; - if (tp) { - driver->termios[i] = NULL; - kfree(tp); - } - tp = driver->termios_locked[i]; - if (tp) { - driver->termios_locked[i] = NULL; - kfree(tp); - } - if (!(driver->flags & TTY_DRIVER_NO_DEVFS)) - tty_unregister_device(driver, i); - } - p = driver->ttys; - proc_tty_unregister_driver(driver); - driver->ttys = NULL; - driver->termios = driver->termios_locked = NULL; - kfree(p); - cdev_del(&driver->cdev); - return 0; -} - -EXPORT_SYMBOL(tty_unregister_driver); - - -/* - * Initialize the console device. This is called *early*, so - * we can't necessarily depend on lots of kernel help here. - * Just do some early initializations, and do the complex setup - * later. - */ -void __init console_init(void) -{ - initcall_t *call; - - /* Setup the default TTY line discipline. */ - (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); - - /* - * set up the console device so that later boot sequences can - * inform about problems etc.. - */ -#ifdef CONFIG_EARLY_PRINTK - disable_early_printk(); -#endif - call = __con_initcall_start; - while (call < __con_initcall_end) { - (*call)(); - call++; - } -} - -#ifdef CONFIG_VT -extern int vty_init(void); -#endif - -static int __init tty_class_init(void) -{ - tty_class = class_create(THIS_MODULE, "tty"); - if (IS_ERR(tty_class)) - return PTR_ERR(tty_class); - return 0; -} - -postcore_initcall(tty_class_init); - -/* 3/2004 jmc: why do these devices exist? */ - -static struct cdev tty_cdev, console_cdev; -#ifdef CONFIG_UNIX98_PTYS -static struct cdev ptmx_cdev; -#endif -#ifdef CONFIG_VT -static struct cdev vc0_cdev; -#endif - -/* - * Ok, now we can initialize the rest of the tty devices and can count - * on memory allocations, interrupts etc.. - */ -static int __init tty_init(void) -{ - cdev_init(&tty_cdev, &tty_fops); - if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) - panic("Couldn't register /dev/tty driver\n"); - devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); - - cdev_init(&console_cdev, &console_fops); - if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) - panic("Couldn't register /dev/console driver\n"); - devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); - -#ifdef CONFIG_UNIX98_PTYS - cdev_init(&ptmx_cdev, &ptmx_fops); - if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) - panic("Couldn't register /dev/ptmx driver\n"); - devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); -#endif - -#ifdef CONFIG_VT - if (!console_use_vt) - goto out_vt; - cdev_init(&vc0_cdev, &console_fops); - if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || - register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) - panic("Couldn't register /dev/tty0 driver\n"); - devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); - - vty_init(); - out_vt: -#endif - return 0; -} -module_init(tty_init); diff --git a/linux-2.6-xen-sparse/drivers/xen/Kconfig b/linux-2.6-xen-sparse/drivers/xen/Kconfig index 647dce8386..907d4b5757 100644 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig @@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND dedicated device-driver domain, or your master control domain (domain 0), then you almost certainly want to say Y here. +config XEN_FRAMEBUFFER + tristate "Framebuffer-device frontend driver" + depends on XEN && FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + default y + help + The framebuffer-device frontend drivers allows the kernel to create a + virtual framebuffer. This framebuffer can be viewed in another + domain. Unless this domain has access to a real video card, you + probably want to say Y here. + +config XEN_KEYBOARD + tristate "Keyboard-device frontend driver" + depends on XEN && XEN_FRAMEBUFFER && INPUT + default y + help + The keyboard-device frontend driver allows the kernel to create a + virtual keyboard. This keyboard can then be driven by another + domain. If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably + want to say Y here. + config XEN_SCRUB_PAGES bool "Scrub memory before freeing it to Xen" default y diff --git a/linux-2.6-xen-sparse/drivers/xen/Makefile b/linux-2.6-xen-sparse/drivers/xen/Makefile index 79eddeec16..cfae4625c4 100644 --- a/linux-2.6-xen-sparse/drivers/xen/Makefile +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/ obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback/ obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += pcifront/ +obj-$(CONFIG_XEN_FRAMEBUFFER) += fbfront/ +obj-$(CONFIG_XEN_KEYBOARD) += fbfront/ diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c index cf5b63a997..f184f6ac35 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c @@ -57,6 +57,7 @@ #include #include #include +#include #include /* @@ -698,6 +699,15 @@ static int __init xencons_init(void) printk("Xen virtual console successfully installed as %s%d\n", DRV(xencons_driver)->name, xc_num); + /* Check about framebuffer messing up the console */ + if (!is_initial_xendomain() && + !xenbus_exists(XBT_NIL, "device", "vfb")) { + /* FIXME: this is ugly */ + unregister_console(&kcons_info); + kcons_info.flags |= CON_CONSDEV; + register_console(&kcons_info); + } + return 0; } diff --git a/linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile b/linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile new file mode 100644 index 0000000000..e2b890942f --- /dev/null +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o +obj-$(CONFIG_XEN_KEYBOARD) += xenkbd.o diff --git a/linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c new file mode 100644 index 0000000000..9c8bfbe9a2 --- /dev/null +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c @@ -0,0 +1,682 @@ +/* + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device + * + * Copyright (C) 2005-2006 Anthony Liguori + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster + * + * Based on linux/drivers/video/q40fb.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +/* + * TODO: + * + * Switch to grant tables when they become capable of dealing with the + * frame buffer. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct xenfb_mapping +{ + struct list_head link; + struct vm_area_struct *vma; + atomic_t map_refs; + int faults; + struct xenfb_info *info; +}; + +struct xenfb_info +{ + struct task_struct *kthread; + wait_queue_head_t wq; + + unsigned char *fb; + struct fb_info *fb_info; + struct timer_list refresh; + int dirty; + int x1, y1, x2, y2; /* dirty rectangle, + protected by mm_lock */ + spinlock_t mm_lock; + int nr_pages; + struct page **pages; + struct list_head mappings; /* protected by mm_lock */ + + unsigned evtchn; + int irq; + struct xenfb_page *page; + unsigned long *mfns; + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ + + struct xenbus_device *xbdev; +}; + +static int xenfb_fps = 20; +static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; + +static int xenfb_remove(struct xenbus_device *); +static void xenfb_init_shared_page(struct xenfb_info *); +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); +static void xenfb_disconnect_backend(struct xenfb_info *); + +static void xenfb_do_update(struct xenfb_info *info, + int x, int y, int w, int h) +{ + union xenfb_out_event event; + __u32 prod; + + event.type = XENFB_TYPE_UPDATE; + event.update.x = x; + event.update.y = y; + event.update.width = w; + event.update.height = h; + + prod = info->page->out_prod; + /* caller ensures !xenfb_queue_full() */ + mb(); /* ensure ring space available */ + XENFB_OUT_RING_REF(info->page, prod) = event; + wmb(); /* ensure ring contents visible */ + info->page->out_prod = prod + 1; + + notify_remote_via_evtchn(info->evtchn); +} + +static int xenfb_queue_full(struct xenfb_info *info) +{ + __u32 cons, prod; + + prod = info->page->out_prod; + cons = info->page->out_cons; + return prod - cons == XENFB_OUT_RING_LEN; +} + +static void xenfb_update_screen(struct xenfb_info *info) +{ + unsigned long flags; + int y1, y2, x1, x2; + struct xenfb_mapping *map; + + if (!info->update_wanted) + return; + if (xenfb_queue_full(info)) + return; + + spin_lock_irqsave(&info->mm_lock, flags); + + y1 = info->y1; + y2 = info->y2; + x1 = info->x1; + x2 = info->x2; + info->x1 = info->y1 = INT_MAX; + info->x2 = info->y2 = 0; + + list_for_each_entry(map, &info->mappings, link) { + if (!map->faults) + continue; + zap_page_range(map->vma, map->vma->vm_start, + map->vma->vm_end - map->vma->vm_start, NULL); + map->faults = 0; + } + + spin_unlock_irqrestore(&info->mm_lock, flags); + + xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); +} + +static int xenfb_thread(void *data) +{ + struct xenfb_info *info = data; + + while (!kthread_should_stop()) { + if (info->dirty) { + info->dirty = 0; + xenfb_update_screen(info); + } + wait_event_interruptible(info->wq, + kthread_should_stop() || info->dirty); + try_to_freeze(); + } + return 0; +} + +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 v; + + if (regno > info->cmap.len) + return 1; + + red >>= (16 - info->var.red.length); + green >>= (16 - info->var.green.length); + blue >>= (16 - info->var.blue.length); + + v = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset); + + /* FIXME is this sane? check against xxxfb_setcolreg()! */ + switch (info->var.bits_per_pixel) { + case 16: + case 24: + case 32: + ((u32 *)info->pseudo_palette)[regno] = v; + break; + } + + return 0; +} + +static void xenfb_timer(unsigned long data) +{ + struct xenfb_info *info = (struct xenfb_info *)data; + info->dirty = 1; + wake_up(&info->wq); +} + +static void __xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + int y2, x2; + + y2 = y1 + h; + x2 = x1 + w; + + if (info->y1 > y1) + info->y1 = y1; + if (info->y2 < y2) + info->y2 = y2; + if (info->x1 > x1) + info->x1 = x1; + if (info->x2 < x2) + info->x2 = x2; + + if (timer_pending(&info->refresh)) + return; + + mod_timer(&info->refresh, jiffies + HZ/xenfb_fps); +} + +static void xenfb_refresh(struct xenfb_info *info, + int x1, int y1, int w, int h) +{ + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + __xenfb_refresh(info, x1, y1, w, h); + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + struct xenfb_info *info = p->par; + + cfb_fillrect(p, rect); + xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); +} + +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) +{ + struct xenfb_info *info = p->par; + + cfb_imageblit(p, image); + xenfb_refresh(info, image->dx, image->dy, image->width, image->height); +} + +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + struct xenfb_info *info = p->par; + + cfb_copyarea(p, area); + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); +} + +static void xenfb_vm_open(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + atomic_inc(&map->map_refs); +} + +static void xenfb_vm_close(struct vm_area_struct *vma) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + unsigned long flags; + + spin_lock_irqsave(&info->mm_lock, flags); + if (atomic_dec_and_test(&map->map_refs)) { + list_del(&map->link); + kfree(map); + } + spin_unlock_irqrestore(&info->mm_lock, flags); +} + +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma, + unsigned long vaddr, int *type) +{ + struct xenfb_mapping *map = vma->vm_private_data; + struct xenfb_info *info = map->info; + int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT; + unsigned long flags; + struct page *page; + int y1, y2; + + if (pgnr >= info->nr_pages) + return NOPAGE_SIGBUS; + + spin_lock_irqsave(&info->mm_lock, flags); + page = info->pages[pgnr]; + get_page(page); + map->faults++; + + y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length; + y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length; + if (y2 > info->fb_info->var.yres) + y2 = info->fb_info->var.yres; + __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1); + spin_unlock_irqrestore(&info->mm_lock, flags); + + if (type) + *type = VM_FAULT_MINOR; + + return page; +} + +static struct vm_operations_struct xenfb_vm_ops = { + .open = xenfb_vm_open, + .close = xenfb_vm_close, + .nopage = xenfb_vm_nopage, +}; + +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma) +{ + struct xenfb_info *info = fb_info->par; + unsigned long flags; + struct xenfb_mapping *map; + int map_pages; + + if (!(vma->vm_flags & VM_WRITE)) + return -EINVAL; + if (!(vma->vm_flags & VM_SHARED)) + return -EINVAL; + if (vma->vm_pgoff != 0) + return -EINVAL; + + map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT; + if (map_pages > info->nr_pages) + return -EINVAL; + + map = kzalloc(sizeof(*map), GFP_KERNEL); + if (map == NULL) + return -ENOMEM; + + map->vma = vma; + map->faults = 0; + map->info = info; + atomic_set(&map->map_refs, 1); + + spin_lock_irqsave(&info->mm_lock, flags); + list_add(&map->link, &info->mappings); + spin_unlock_irqrestore(&info->mm_lock, flags); + + vma->vm_ops = &xenfb_vm_ops; + vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED); + vma->vm_private_data = map; + + return 0; +} + +static struct fb_ops xenfb_fb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = xenfb_setcolreg, + .fb_fillrect = xenfb_fillrect, + .fb_copyarea = xenfb_copyarea, + .fb_imageblit = xenfb_imageblit, + .fb_mmap = xenfb_mmap, +}; + +static irqreturn_t xenfb_event_handler(int rq, void *dev_id, + struct pt_regs *regs) +{ + /* + * No in events recognized, simply ignore them all. + * If you need to recognize some, see xenbkd's input_handler() + * for how to do that. + */ + struct xenfb_info *info = dev_id; + struct xenfb_page *page = info->page; + + if (page->in_cons != page->in_prod) { + info->page->in_cons = info->page->in_prod; + notify_remote_via_evtchn(info->evtchn); + } + return IRQ_HANDLED; +} + +static unsigned long vmalloc_to_mfn(void *address) +{ + return pfn_to_mfn(vmalloc_to_pfn(address)); +} + +static int __devinit xenfb_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + struct xenfb_info *info; + struct fb_info *fb_info; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + info->irq = -1; + info->x1 = info->y1 = INT_MAX; + spin_lock_init(&info->mm_lock); + init_waitqueue_head(&info->wq); + init_timer(&info->refresh); + info->refresh.function = xenfb_timer; + info->refresh.data = (unsigned long)info; + INIT_LIST_HEAD(&info->mappings); + + info->fb = vmalloc(xenfb_mem_len); + if (info->fb == NULL) + goto error_nomem; + memset(info->fb, 0, xenfb_mem_len); + + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; + + info->pages = kmalloc(sizeof(struct page *) * info->nr_pages, + GFP_KERNEL); + if (info->pages == NULL) + goto error_nomem; + + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->mfns) + goto error_nomem; + + /* set up shared page */ + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + + xenfb_init_shared_page(info); + + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); + /* see fishy hackery below */ + if (fb_info == NULL) + goto error_nomem; + + /* FIXME fishy hackery */ + fb_info->pseudo_palette = fb_info->par; + fb_info->par = info; + /* /FIXME */ + fb_info->screen_base = info->fb; + + fb_info->fbops = &xenfb_fb_ops; + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; + fb_info->var.bits_per_pixel = info->page->depth; + + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; + + fb_info->var.activate = FB_ACTIVATE_NOW; + fb_info->var.height = -1; + fb_info->var.width = -1; + fb_info->var.vmode = FB_VMODE_NONINTERLACED; + + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; + fb_info->fix.line_length = info->page->line_length; + fb_info->fix.smem_start = 0; + fb_info->fix.smem_len = xenfb_mem_len; + strcpy(fb_info->fix.id, "xen"); + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; + fb_info->fix.accel = FB_ACCEL_NONE; + + fb_info->flags = FBINFO_FLAG_DEFAULT; + + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); + if (ret < 0) { + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); + goto error; + } + + ret = register_framebuffer(fb_info); + if (ret) { + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(fb_info); + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + info->fb_info = fb_info; + + /* FIXME should this be delayed until backend XenbusStateConnected? */ + info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); + if (IS_ERR(info->kthread)) { + ret = PTR_ERR(info->kthread); + info->kthread = NULL; + xenbus_dev_fatal(dev, ret, "register_framebuffer"); + goto error; + } + + ret = xenfb_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenfb_remove(dev); + return ret; +} + +static int xenfb_resume(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + xenfb_disconnect_backend(info); + xenfb_init_shared_page(info); + return xenfb_connect_backend(dev, info); +} + +static int xenfb_remove(struct xenbus_device *dev) +{ + struct xenfb_info *info = dev->dev.driver_data; + + del_timer(&info->refresh); + if (info->kthread) + kthread_stop(info->kthread); + xenfb_disconnect_backend(info); + if (info->fb_info) { + unregister_framebuffer(info->fb_info); + fb_dealloc_cmap(&info->fb_info->cmap); + framebuffer_release(info->fb_info); + } + free_page((unsigned long)info->page); + vfree(info->mfns); + kfree(info->pages); + vfree(info->fb); + kfree(info); + + return 0; +} + +static void xenfb_init_shared_page(struct xenfb_info *info) +{ + int i; + + for (i = 0; i < info->nr_pages; i++) + info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE); + + for (i = 0; i < info->nr_pages; i++) + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + + info->page->pd[0] = vmalloc_to_mfn(info->mfns); + info->page->pd[1] = 0; + info->page->width = XENFB_WIDTH; + info->page->height = XENFB_HEIGHT; + info->page->depth = XENFB_DEPTH; + info->page->line_length = (info->page->depth / 8) * info->page->width; + info->page->mem_length = xenfb_mem_len; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; +} + +static int xenfb_connect_backend(struct xenbus_device *dev, + struct xenfb_info *info) +{ + int ret; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler, + 0, "xenfb", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenfb_disconnect_backend(struct xenfb_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenfb_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenfb_info *info = dev->dev.driver_data; + int val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + InitWait: + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "request-update", "%d", &val) < 0) + val = 0; + if (val) + info->update_wanted = 1; + break; + + case XenbusStateClosing: + // FIXME is this safe in any dev->state? + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenfb_ids[] = { + { "vfb" }, + { "" } +}; + +static struct xenbus_driver xenfb = { + .name = "vfb", + .owner = THIS_MODULE, + .ids = xenfb_ids, + .probe = xenfb_probe, + .remove = xenfb_remove, + .resume = xenfb_resume, + .otherend_changed = xenfb_backend_changed, +}; + +static int __init xenfb_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenfb); +} + +static void __exit xenfb_cleanup(void) +{ + return xenbus_unregister_driver(&xenfb); +} + +module_init(xenfb_init); +module_exit(xenfb_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c new file mode 100644 index 0000000000..7737732e34 --- /dev/null +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c @@ -0,0 +1,300 @@ +/* + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster + * + * Based on linux/drivers/input/mouse/sermouse.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +/* + * TODO: + * + * Switch to grant tables together with xenfb.c. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct xenkbd_info +{ + struct input_dev *dev; + struct xenkbd_page *page; + unsigned evtchn; + int irq; + struct xenbus_device *xbdev; +}; + +static int xenkbd_remove(struct xenbus_device *); +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); +static void xenkbd_disconnect_backend(struct xenkbd_info *); + +/* + * Note: if you need to send out events, see xenfb_do_update() for how + * to do that. + */ + +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs) +{ + struct xenkbd_info *info = dev_id; + struct xenkbd_page *page = info->page; + __u32 cons, prod; + + prod = page->in_prod; + if (prod == page->out_cons) + return IRQ_HANDLED; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->in_cons; cons != prod; cons++) { + union xenkbd_in_event *event; + event = &XENKBD_IN_RING_REF(page, cons); + + switch (event->type) { + case XENKBD_TYPE_MOTION: + input_report_rel(info->dev, REL_X, event->motion.rel_x); + input_report_rel(info->dev, REL_Y, event->motion.rel_y); + break; + case XENKBD_TYPE_KEY: + input_report_key(info->dev, event->key.keycode, event->key.pressed); + break; + case XENKBD_TYPE_POS: + input_report_abs(info->dev, ABS_X, event->pos.abs_x); + input_report_abs(info->dev, ABS_Y, event->pos.abs_y); + break; + } + } + input_sync(info->dev); + mb(); /* ensure we got ring contents */ + page->in_cons = cons; + notify_remote_via_evtchn(info->evtchn); + + return IRQ_HANDLED; +} + +int __devinit xenkbd_probe(struct xenbus_device *dev, + const struct xenbus_device_id *id) +{ + int ret, i; + struct xenkbd_info *info; + struct input_dev *input_dev; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); + return -ENOMEM; + } + dev->dev.driver_data = info; + info->xbdev = dev; + + info->page = (void *)__get_free_page(GFP_KERNEL); + if (!info->page) + goto error_nomem; + info->page->in_cons = info->page->in_prod = 0; + info->page->out_cons = info->page->out_prod = 0; + + input_dev = input_allocate_device(); + if (!input_dev) + goto error_nomem; + + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); + input_dev->keybit[LONG(BTN_MOUSE)] + = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + /* TODO additional buttons */ + input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + + /* FIXME not sure this is quite right */ + for (i = 0; i < 256; i++) + set_bit(i, input_dev->keybit); + + input_dev->name = "Xen Virtual Keyboard/Mouse"; + + input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0); + + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + xenbus_dev_fatal(dev, ret, "input_register_device"); + goto error; + } + info->dev = input_dev; + + ret = xenkbd_connect_backend(dev, info); + if (ret < 0) + goto error; + + return 0; + + error_nomem: + ret = -ENOMEM; + xenbus_dev_fatal(dev, ret, "allocating device memory"); + error: + xenkbd_remove(dev); + return ret; +} + +static int xenkbd_resume(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + xenkbd_disconnect_backend(info); + return xenkbd_connect_backend(dev, info); +} + +static int xenkbd_remove(struct xenbus_device *dev) +{ + struct xenkbd_info *info = dev->dev.driver_data; + + xenkbd_disconnect_backend(info); + input_unregister_device(info->dev); + free_page((unsigned long)info->page); + kfree(info); + return 0; +} + +static int xenkbd_connect_backend(struct xenbus_device *dev, + struct xenkbd_info *info) +{ + int ret; + struct xenbus_transaction xbt; + + ret = xenbus_alloc_evtchn(dev, &info->evtchn); + if (ret) + return ret; + ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0, + "xenkbd", info); + if (ret < 0) { + xenbus_free_evtchn(dev, info->evtchn); + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); + return ret; + } + info->irq = ret; + + again: + ret = xenbus_transaction_start(&xbt); + if (ret) { + xenbus_dev_fatal(dev, ret, "starting transaction"); + return ret; + } + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", + virt_to_mfn(info->page)); + if (ret) + goto error_xenbus; + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", + info->evtchn); + if (ret) + goto error_xenbus; + ret = xenbus_transaction_end(xbt, 0); + if (ret) { + if (ret == -EAGAIN) + goto again; + xenbus_dev_fatal(dev, ret, "completing transaction"); + return ret; + } + + xenbus_switch_state(dev, XenbusStateInitialised); + return 0; + + error_xenbus: + xenbus_transaction_end(xbt, 1); + xenbus_dev_fatal(dev, ret, "writing xenstore"); + return ret; +} + +static void xenkbd_disconnect_backend(struct xenkbd_info *info) +{ + if (info->irq >= 0) + unbind_from_irqhandler(info->irq, info); + info->irq = -1; +} + +static void xenkbd_backend_changed(struct xenbus_device *dev, + enum xenbus_state backend_state) +{ + struct xenkbd_info *info = dev->dev.driver_data; + int ret, val; + + switch (backend_state) { + case XenbusStateInitialising: + case XenbusStateInitialised: + case XenbusStateUnknown: + case XenbusStateClosed: + break; + + case XenbusStateInitWait: + InitWait: + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, + "feature-abs-pointer", "%d", &val); + if (ret < 0) + val = 0; + if (val) { + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, + "request-abs-pointer", "1"); + if (ret) + ; /* FIXME */ + } + xenbus_switch_state(dev, XenbusStateConnected); + break; + + case XenbusStateConnected: + /* + * Work around xenbus race condition: If backend goes + * through InitWait to Connected fast enough, we can + * get Connected twice here. + */ + if (dev->state != XenbusStateConnected) + goto InitWait; /* no InitWait seen yet, fudge it */ + break; + + case XenbusStateClosing: + xenbus_frontend_closed(dev); + break; + } +} + +static struct xenbus_device_id xenkbd_ids[] = { + { "vkbd" }, + { "" } +}; + +static struct xenbus_driver xenkbd = { + .name = "vkbd", + .owner = THIS_MODULE, + .ids = xenkbd_ids, + .probe = xenkbd_probe, + .remove = xenkbd_remove, + .resume = xenkbd_resume, + .otherend_changed = xenkbd_backend_changed, +}; + +static int __init xenkbd_init(void) +{ + if (!is_running_on_xen()) + return -ENODEV; + + /* Nothing to do if running in dom0. */ + if (is_initial_xendomain()) + return -ENODEV; + + return xenbus_register_frontend(&xenkbd); +} + +static void __exit xenkbd_cleanup(void) +{ + return xenbus_unregister_driver(&xenkbd); +} + +module_init(xenkbd_init); +module_exit(xenkbd_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/linux-2.6-xen-sparse/mm/memory.c b/linux-2.6-xen-sparse/mm/memory.c index d7319d32f9..d44d1ce44f 100644 --- a/linux-2.6-xen-sparse/mm/memory.c +++ b/linux-2.6-xen-sparse/mm/memory.c @@ -882,6 +882,7 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, tlb_finish_mmu(tlb, address, end); return end; } +EXPORT_SYMBOL(zap_page_range); /* * Do a quick page-table lookup for a single page. diff --git a/tools/Makefile b/tools/Makefile index 0eae0edff5..29ce67dfe2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -19,6 +19,7 @@ SUBDIRS-y += xenstat SUBDIRS-y += libaio SUBDIRS-y += blktap SUBDIRS-y += libfsimage +SUBDIRS-y += xenfb SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen # These don't cross-compile diff --git a/tools/python/xen/xend/XendDevices.py b/tools/python/xen/xend/XendDevices.py index ce91e28271..7b362ad727 100644 --- a/tools/python/xen/xend/XendDevices.py +++ b/tools/python/xen/xend/XendDevices.py @@ -19,7 +19,7 @@ # A collection of DevControllers # -from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif +from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif, vfbif from xen.xend.server.BlktapController import BlktapController class XendDevices: @@ -41,6 +41,8 @@ class XendDevices: 'irq': irqif.IRQController, 'usb': usbif.UsbifController, 'tap': BlktapController, + 'vfb': vfbif.VfbifController, + 'vkbd': vfbif.VkbdifController, } #@classmethod diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index d606dbb7bb..152022477e 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -458,7 +458,7 @@ class XendDomainInfo: try: self._constructDomain() self._storeVmDetails() - self._createDevices() + self._restoreDomain() self._createChannels() self._storeDomDetails() self._endRestore() @@ -1387,6 +1387,23 @@ class XendDomainInfo: raise VmError(str(exn)) + def _restoreDomain(self): + log.debug('XendDomainInfo.restoreDomain: %s %s', + self.domid, + self.info['cpu_weight']) + + if not self.infoIsSet('image'): + raise VmError('Missing image in configuration') + + try: + self.image = image.create(self, + self.info['image'], + self.info['device']) + + self._createDevices() + except RuntimeError, exn: + raise VmError(str(exn)) + def cleanupDomain(self): """Cleanup domain resources; release devices. Idempotent. Nothrow guarantee.""" diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 31194c7a73..10acfd6674 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -23,6 +23,7 @@ import math import signal import xen.lowlevel.xc +import xen.util.auxbin from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS from xen.xend.XendError import VmError, XendError from xen.xend.XendLogging import log @@ -199,6 +200,79 @@ class LinuxImageHandler(ImageHandler): ramdisk = self.ramdisk, features = self.vm.getFeatures()) + def configure(self, imageConfig, deviceConfig): + ImageHandler.configure(self, imageConfig, deviceConfig) + + self.pid = 0 + log.info("configuring linux guest") + + # set up the graphics bits. + # FIXME: this is much like what we do for HVM, should it be + # for all image types now? + self.display = sxp.child_value(imageConfig, 'display') + self.xauthority = sxp.child_value(imageConfig, 'xauthority') + self.vncconsole = sxp.child_value(imageConfig, 'vncconsole') + vncpasswd = sxp.child_value(imageConfig, 'vncpasswd') + self.vncpasswd = vncpasswd + + self.vnc = sxp.child_value(imageConfig, 'vnc') + self.sdl = sxp.child_value(imageConfig, 'sdl') + if self.vnc: + self.vncdisplay = int(sxp.child_value(imageConfig, 'vncdisplay', + self.vm.getDomid())) + self.vncunused = sxp.child_value(imageConfig, 'vncunused') + self.vnclisten = sxp.child_value(imageConfig, 'vnclisten') + if not(self.vnclisten): + self.vnclisten = xen.xend.XendRoot.instance().get_vnclisten_address() + + def createDeviceModel(self): + if self.pid: + return + # Execute device model (for us, it's just the fb frontend) + if not self.vnc and not self.sdl: + return + + if self.vnc: + args = [xen.util.auxbin.pathTo("xen-vncfb")] + if self.vncunused: + args += ['--unused'] + elif self.vncdisplay: + args += [ "--vncport", "%d" %(5900 + self.vncdisplay,) ] + if self.vnclisten: + args += [ "--listen", self.vnclisten ] + + # password check + if self.vncpasswd is None: + # get password from xend-config(if password omitted, None) + self.vncpasswd = xen.xend.XendRoot.instance().get_vncpasswd_default() + + if self.vncpasswd is None: + raise VmError('vncpasswd is not setup in the guest config or xend-config.') + if self.vncpasswd != '': + self.vm.storeVm("vncpasswd", self.vncpasswd) + log.info("vncpassword set to '%s'", self.vncpasswd) + + elif self.sdl: + args = [xen.util.auxbin.pathTo("xen-sdlfb")] + args = args + [ "--domid", "%d" % self.vm.getDomid(), + "--title", self.vm.info['name'] ] + + env = dict(os.environ) + if self.display: + env['DISPLAY'] = self.display + if self.xauthority: + env['XAUTHORITY'] = self.xauthority + log.info("spawning video: %s", args) + self.pid = os.spawnve(os.P_NOWAIT, args[0], args, env) + log.info("device model pid: %d", self.pid) + + def destroy(self): + if not self.pid: + return + os.kill(self.pid, signal.SIGKILL) + os.waitpid(self.pid, 0) + self.pid = 0 + class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" diff --git a/tools/python/xen/xend/server/vfbif.py b/tools/python/xen/xend/server/vfbif.py new file mode 100644 index 0000000000..7f9691698f --- /dev/null +++ b/tools/python/xen/xend/server/vfbif.py @@ -0,0 +1,29 @@ +from xen.xend.server.DevController import DevController + +class VfbifController(DevController): + """Virtual frame buffer controller. Handles all vfb devices for a domain. + """ + + def __init__(self, vm): + DevController.__init__(self, vm) + + def getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" + devid = 0 + back = {} + front = {} + return (devid, back, front) + +class VkbdifController(DevController): + """Virtual keyboard controller. Handles all vkbd devices for a domain. + """ + + def __init__(self, vm): + DevController.__init__(self, vm) + + def getDeviceDetails(self, config): + """@see DevController.getDeviceDetails""" + devid = 0 + back = {} + front = {} + return (devid, back, front) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index e1df262c8f..c4bca1130a 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -284,6 +284,14 @@ gopts.var('usbport', val='PATH', use="""Add a physical USB port to a domain, as specified by the path to that port. This option may be repeated to add more than one port.""") +gopts.var('vfb', val="no|yes'", + fn=set_bool, default=0, + use="Make the domain a framebuffer backend.") + +gopts.var('vkbd', val="no|yes'", + fn=set_bool, default=0, + use="Make the domain a keyboard backend.") + gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME", fn=append_value, default=[], use="""Add a network interface with the given MAC address and bridge. @@ -512,8 +520,10 @@ def configure_image(vals): config_image.append(['args', vals.extra]) if vals.builder == 'hvm': - configure_hvm(config_image, vals) - + configure_hvm(config_image, vals) + + configure_graphics(config_image, vals) + return config_image def configure_disks(config_devs, vals): @@ -564,6 +574,13 @@ def configure_usb(config_devs, vals): config_usb = ['usbport', ['path', path]] config_devs.append(['device', config_usb]) +def configure_vfbs(config_devs, vals): + if vals.vfb: + config_devs.append(['device', ['vfb', []]]) + +def configure_vkbds(config_devs, vals): + if vals.vkbd: + config_devs.append(['device', ['vkbd', []]]) def configure_security(config, vals): """Create the config for ACM security labels. @@ -661,13 +678,20 @@ def configure_vifs(config_devs, vals): config_devs.append(['device', config_vif]) +def configure_graphics(config_image, vals): + """Create the config for graphic consoles. + """ + args = [ 'vnc', 'vncdisplay', 'vncconsole', 'vncunused', + 'sdl', 'display', 'xauthority', 'vnclisten', 'vncpasswd'] + for a in args: + if (vals.__dict__[a]): + config_image.append([a, vals.__dict__[a]]) + def configure_hvm(config_image, vals): """Create the config for HVM devices. """ args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw', - 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten', - 'sdl', 'display', 'xauthority', 'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ] for a in args: if a in vals.__dict__ and vals.__dict__[a] is not None: @@ -742,6 +766,8 @@ def make_config(vals): configure_vifs(config_devs, vals) configure_usb(config_devs, vals) configure_vtpm(config_devs, vals) + configure_vfbs(config_devs, vals) + configure_vkbds(config_devs, vals) configure_security(config, vals) config += config_devs diff --git a/tools/xenfb/Makefile b/tools/xenfb/Makefile new file mode 100644 index 0000000000..dc2547a864 --- /dev/null +++ b/tools/xenfb/Makefile @@ -0,0 +1,35 @@ +XEN_ROOT=../.. +include $(XEN_ROOT)/tools/Rules.mk + +CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -I$(XEN_ROOT)/linux-2.6-xen-sparse/include +LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE) + +INSTALL = install +INSTALL_PROG = $(INSTALL) -m0755 +INSTALL_DIR = $(INSTALL) -d -m0755 + +.PHONY: all +all: build + +.PHONY: build +build: mk-symlinks + $(MAKE) vncfb sdlfb + +install: all + $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)/xen/bin + $(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb + $(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb + +sdlfb: sdlfb.o xenfb.o + +sdlfb.o: CFLAGS += $(shell sdl-config --cflags) +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore + +clean: + $(RM) *.o *~ vncfb sdlfb + +vncfb: vncfb.o xenfb.o +vncfb.o: CFLAGS += $(shell libvncserver-config --cflags) +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore + +sdlfb.o xenfb.o vncfb.o: xenfb.h diff --git a/tools/xenfb/sdlfb.c b/tools/xenfb/sdlfb.c new file mode 100644 index 0000000000..cc5f8d6f52 --- /dev/null +++ b/tools/xenfb/sdlfb.c @@ -0,0 +1,334 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "xenfb.h" + +struct SDLFBData +{ + SDL_Surface *dst; + SDL_Surface *src; +}; + +/* + * Map from scancode to Linux input layer keycode. Scancodes are + * hardware-specific. This map assumes a standard AT or PS/2 + * keyboard. + * + * Why use scancodes? We can't use key symbols, because they don't + * identify keys --- they're what keys are mapped to. The standard + * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to + * SDLK_LESS. + */ +static int keymap[256] = { + [9] = KEY_ESC, + [10] = KEY_1, + [11] = KEY_2, + [12] = KEY_3, + [13] = KEY_4, + [14] = KEY_5, + [15] = KEY_6, + [16] = KEY_7, + [17] = KEY_8, + [18] = KEY_9, + [19] = KEY_0, + [20] = KEY_MINUS, + [21] = KEY_EQUAL, + [22] = KEY_BACKSPACE, + [23] = KEY_TAB, + [24] = KEY_Q, + [25] = KEY_W, + [26] = KEY_E, + [27] = KEY_R, + [28] = KEY_T, + [29] = KEY_Y, + [30] = KEY_U, + [31] = KEY_I, + [32] = KEY_O, + [33] = KEY_P, + [34] = KEY_LEFTBRACE, + [35] = KEY_RIGHTBRACE, + [36] = KEY_ENTER, + [37] = KEY_LEFTCTRL, + [38] = KEY_A, + [39] = KEY_S, + [40] = KEY_D, + [41] = KEY_F, + [42] = KEY_G, + [43] = KEY_H, + [44] = KEY_J, + [45] = KEY_K, + [46] = KEY_L, + [47] = KEY_SEMICOLON, + [48] = KEY_APOSTROPHE, + [49] = KEY_GRAVE, + [50] = KEY_LEFTSHIFT, + [51] = KEY_BACKSLASH, + [52] = KEY_Z, + [53] = KEY_X, + [54] = KEY_C, + [55] = KEY_V, + [56] = KEY_B, + [57] = KEY_N, + [58] = KEY_M, + [59] = KEY_COMMA, + [60] = KEY_DOT, + [61] = KEY_SLASH, + [62] = KEY_RIGHTSHIFT, + [63] = KEY_KPASTERISK, + [64] = KEY_LEFTALT, + [65] = KEY_SPACE, + [66] = KEY_CAPSLOCK, + [67] = KEY_F1, + [68] = KEY_F2, + [69] = KEY_F3, + [70] = KEY_F4, + [71] = KEY_F5, + [72] = KEY_F6, + [73] = KEY_F7, + [74] = KEY_F8, + [75] = KEY_F9, + [76] = KEY_F10, + [77] = KEY_NUMLOCK, + [78] = KEY_SCROLLLOCK, + [79] = KEY_KP7, + [80] = KEY_KP8, + [81] = KEY_KP9, + [82] = KEY_KPMINUS, + [83] = KEY_KP4, + [84] = KEY_KP5, + [85] = KEY_KP6, + [86] = KEY_KPPLUS, + [87] = KEY_KP1, + [88] = KEY_KP2, + [89] = KEY_KP3, + [90] = KEY_KP0, + [91] = KEY_KPDOT, + [94] = KEY_102ND, /* FIXME is this correct? */ + [95] = KEY_F11, + [96] = KEY_F12, + [108] = KEY_KPENTER, + [109] = KEY_RIGHTCTRL, + [112] = KEY_KPSLASH, + [111] = KEY_SYSRQ, + [113] = KEY_RIGHTALT, + [97] = KEY_HOME, + [98] = KEY_UP, + [99] = KEY_PAGEUP, + [100] = KEY_LEFT, + [102] = KEY_RIGHT, + [103] = KEY_END, + [104] = KEY_DOWN, + [105] = KEY_PAGEDOWN, + [106] = KEY_INSERT, + [107] = KEY_DELETE, + [110] = KEY_PAUSE, + [115] = KEY_LEFTMETA, + [116] = KEY_RIGHTMETA, + [117] = KEY_MENU, +}; + +static int btnmap[] = { + [SDL_BUTTON_LEFT] = BTN_LEFT, + [SDL_BUTTON_MIDDLE] = BTN_MIDDLE, + [SDL_BUTTON_RIGHT] = BTN_RIGHT, + /* FIXME not 100% sure about these: */ + [SDL_BUTTON_WHEELUP] = BTN_FORWARD, + [SDL_BUTTON_WHEELDOWN] BTN_BACK +}; + +static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height) +{ + struct SDLFBData *data = xenfb->user_data; + SDL_Rect r = { x, y, width, height }; + SDL_BlitSurface(data->src, &r, data->dst, &r); + SDL_UpdateRect(data->dst, x, y, width, height); +} + +static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event) +{ + int x, y, ret; + + switch (event->type) { + case SDL_KEYDOWN: + case SDL_KEYUP: + if (keymap[event->key.keysym.scancode] == 0) + break; + ret = xenfb_send_key(xenfb, + event->type == SDL_KEYDOWN, + keymap[event->key.keysym.scancode]); + if (ret < 0) + fprintf(stderr, "Key %d %s lost (%s)\n", + keymap[event->key.keysym.scancode], + event->type == SDL_KEYDOWN ? "down" : "up", + strerror(errno)); + break; + case SDL_MOUSEMOTION: + if (xenfb->abs_pointer_wanted) { + SDL_GetMouseState(&x, &y); + ret = xenfb_send_position(xenfb, x, y); + } else { + SDL_GetRelativeMouseState(&x, &y); + ret = xenfb_send_motion(xenfb, x, y); + } + if (ret < 0) + fprintf(stderr, "Pointer to %d,%d lost (%s)\n", + x, y, strerror(errno)); + break; + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap)) + break; + if (btnmap[event->button.button] == 0) + break; + ret = xenfb_send_key(xenfb, + event->type == SDL_MOUSEBUTTONDOWN, + btnmap[event->button.button]); + if (ret < 0) + fprintf(stderr, "Button %d %s lost (%s)\n", + btnmap[event->button.button] - BTN_MOUSE, + event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up", + strerror(errno)); + break; + case SDL_QUIT: + return 0; + } + + return 1; +} + +static struct option options[] = { + { "domid", 1, NULL, 'd' }, + { "title", 1, NULL, 't' }, +}; + +int main(int argc, char **argv) +{ + struct xenfb *xenfb; + int domid = -1; + char * title = NULL; + fd_set readfds; + int nfds; + struct SDLFBData data; + SDL_Rect r; + struct timeval tv; + SDL_Event event; + int do_quit = 0; + int opt; + char *endp; + + while ((opt = getopt_long(argc, argv, "d:t:", options, + NULL)) != -1) { + switch (opt) { + case 'd': + domid = strtol(optarg, &endp, 10); + if (endp == optarg || *endp) { + fprintf(stderr, "Invalid domain id specified\n"); + exit(1); + } + break; + case 't': + title = strdup(optarg); + break; + } + } + if (optind != argc) { + fprintf(stderr, "Invalid options!\n"); + exit(1); + } + if (domid <= 0) { + fprintf(stderr, "Domain ID must be specified!\n"); + exit(1); + } + + xenfb = xenfb_new(); + if (xenfb == NULL) { + fprintf(stderr, "Could not create framebuffer (%s)\n", + strerror(errno)); + exit(1); + } + + if (xenfb_attach_dom(xenfb, domid) < 0) { + fprintf(stderr, "Could not connect to domain (%s)\n", + strerror(errno)); + exit(1); + } + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "Could not initialize SDL\n"); + exit(1); + } + + data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth, + SDL_SWSURFACE); + if (!data.dst) { + fprintf(stderr, "SDL_SetVideoMode failed\n"); + exit(1); + } + + data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels, + xenfb->width, xenfb->height, + xenfb->depth, xenfb->row_stride, + 0xFF0000, 0xFF00, 0xFF, 0); + + if (!data.src) { + fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n"); + exit(1); + } + + if (title == NULL) + title = strdup("xen-sdlfb"); + SDL_WM_SetCaption(title, title); + + r.x = r.y = 0; + r.w = xenfb->width; + r.h = xenfb->height; + SDL_BlitSurface(data.src, &r, data.dst, &r); + SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height); + + xenfb->update = sdl_update; + xenfb->user_data = &data; + + SDL_ShowCursor(0); + + /* + * We need to wait for fds becoming ready or SDL events to + * arrive. We time out the select after 10ms to poll for SDL + * events. Clunky, but works. Could avoid the clunkiness + * with a separate thread. + */ + for (;;) { + FD_ZERO(&readfds); + nfds = xenfb_select_fds(xenfb, &readfds); + tv = (struct timeval){0, 10000}; + + if (select(nfds, &readfds, NULL, NULL, &tv) < 0) { + if (errno == EINTR) + continue; + fprintf(stderr, + "Can't select() on event channel (%s)\n", + strerror(errno)); + break; + } + + while (SDL_PollEvent(&event)) { + if (!sdl_on_event(xenfb, &event)) + do_quit = 1; + } + + if (do_quit) + break; + + xenfb_poll(xenfb, &readfds); + } + + xenfb_delete(xenfb); + + SDL_Quit(); + + return 0; +} diff --git a/tools/xenfb/vncfb.c b/tools/xenfb/vncfb.c new file mode 100644 index 0000000000..2fc970e0cc --- /dev/null +++ b/tools/xenfb/vncfb.c @@ -0,0 +1,393 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xenfb.h" + +static int xk2linux[0x10000] = { + [XK_a] = KEY_A, + [XK_b] = KEY_B, + [XK_c] = KEY_C, + [XK_d] = KEY_D, + [XK_e] = KEY_E, + [XK_f] = KEY_F, + [XK_g] = KEY_G, + [XK_h] = KEY_H, + [XK_i] = KEY_I, + [XK_j] = KEY_J, + [XK_k] = KEY_K, + [XK_l] = KEY_L, + [XK_m] = KEY_M, + [XK_n] = KEY_N, + [XK_o] = KEY_O, + [XK_p] = KEY_P, + [XK_q] = KEY_Q, + [XK_r] = KEY_R, + [XK_s] = KEY_S, + [XK_t] = KEY_T, + [XK_u] = KEY_U, + [XK_v] = KEY_V, + [XK_w] = KEY_W, + [XK_x] = KEY_X, + [XK_y] = KEY_Y, + [XK_z] = KEY_Z, + [XK_A] = KEY_A, + [XK_B] = KEY_B, + [XK_C] = KEY_C, + [XK_D] = KEY_D, + [XK_E] = KEY_E, + [XK_F] = KEY_F, + [XK_G] = KEY_G, + [XK_H] = KEY_H, + [XK_I] = KEY_I, + [XK_J] = KEY_J, + [XK_K] = KEY_K, + [XK_L] = KEY_L, + [XK_M] = KEY_M, + [XK_N] = KEY_N, + [XK_O] = KEY_O, + [XK_P] = KEY_P, + [XK_Q] = KEY_Q, + [XK_R] = KEY_R, + [XK_S] = KEY_S, + [XK_T] = KEY_T, + [XK_U] = KEY_U, + [XK_V] = KEY_V, + [XK_W] = KEY_W, + [XK_X] = KEY_X, + [XK_Y] = KEY_Y, + [XK_Z] = KEY_Z, + [XK_0] = KEY_0, + [XK_1] = KEY_1, + [XK_2] = KEY_2, + [XK_3] = KEY_3, + [XK_4] = KEY_4, + [XK_5] = KEY_5, + [XK_6] = KEY_6, + [XK_7] = KEY_7, + [XK_8] = KEY_8, + [XK_9] = KEY_9, + [XK_Return] = KEY_ENTER, + [XK_BackSpace] = KEY_BACKSPACE, + [XK_Tab] = KEY_TAB, + [XK_Pause] = KEY_PAUSE, + [XK_Delete] = KEY_DELETE, + [XK_slash] = KEY_SLASH, + [XK_minus] = KEY_MINUS, + [XK_equal] = KEY_EQUAL, + [XK_Escape] = KEY_ESC, + [XK_braceleft] = KEY_LEFTBRACE, + [XK_braceright] = KEY_RIGHTBRACE, + [XK_bracketleft] = KEY_LEFTMETA, + [XK_bracketright] = KEY_RIGHTMETA, + [XK_Control_L] = KEY_LEFTCTRL, + [XK_Control_R] = KEY_RIGHTCTRL, + [XK_Shift_L] = KEY_LEFTSHIFT, + [XK_Shift_R] = KEY_RIGHTSHIFT, + [XK_Alt_L] = KEY_LEFTALT, + [XK_Alt_R] = KEY_RIGHTALT, + [XK_semicolon] = KEY_SEMICOLON, + [XK_apostrophe] = KEY_APOSTROPHE, + [XK_grave] = KEY_GRAVE, + [XK_backslash] = KEY_BACKSLASH, + [XK_comma] = KEY_COMMA, + [XK_period] = KEY_DOT, + [XK_space] = KEY_SPACE, + [XK_Caps_Lock] = KEY_CAPSLOCK, + [XK_Num_Lock] = KEY_NUMLOCK, + [XK_Scroll_Lock] = KEY_SCROLLLOCK, + [XK_Sys_Req] = KEY_SYSRQ, + [XK_Linefeed] = KEY_LINEFEED, + [XK_Home] = KEY_HOME, + [XK_Pause] = KEY_PAUSE, + [XK_F1] = KEY_F1, + [XK_F2] = KEY_F2, + [XK_F3] = KEY_F3, + [XK_F4] = KEY_F4, + [XK_F5] = KEY_F5, + [XK_F6] = KEY_F6, + [XK_F7] = KEY_F7, + [XK_F8] = KEY_F8, + [XK_F9] = KEY_F9, + [XK_F10] = KEY_F10, + [XK_F11] = KEY_F11, + [XK_F12] = KEY_F12, + [XK_Up] = KEY_UP, + [XK_Page_Up] = KEY_PAGEUP, + [XK_Left] = KEY_LEFT, + [XK_Right] = KEY_RIGHT, + [XK_End] = KEY_END, + [XK_Down] = KEY_DOWN, + [XK_Page_Down] = KEY_PAGEDOWN, + [XK_Insert] = KEY_INSERT, + [XK_colon] = KEY_SEMICOLON, + [XK_quotedbl] = KEY_APOSTROPHE, + [XK_less] = KEY_COMMA, + [XK_greater] = KEY_DOT, + [XK_question] = KEY_SLASH, + [XK_bar] = KEY_BACKSLASH, + [XK_asciitilde] = KEY_GRAVE, + [XK_exclam] = KEY_1, + [XK_at] = KEY_2, + [XK_numbersign] = KEY_3, + [XK_dollar] = KEY_4, + [XK_percent] = KEY_5, + [XK_asciicircum] = KEY_6, + [XK_ampersand] = KEY_7, + [XK_asterisk] = KEY_8, + [XK_parenleft] = KEY_9, + [XK_parenright] = KEY_0, + [XK_underscore] = KEY_MINUS, + [XK_plus] = KEY_EQUAL, +}; + +static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl) +{ + /* + * We need to map to the key's Linux input layer keycode. + * Unfortunately, we don't get the key here, only the + * rfbKeySym, which is what the key is mapped to. Mapping + * back to the key is impossible in general, even when you + * know the keymap. For instance, the standard German keymap + * maps both KEY_COMMA and KEY_102ND to XK_less. We simply + * assume standard US layout. This sucks. + */ + rfbScreenInfoPtr server = cl->screen; + struct xenfb *xenfb = server->screenData; + if (keycode >= sizeof(xk2linux) / sizeof(*xk2linux)) + return; + if (xk2linux[keycode] == 0) + return; + if (xenfb_send_key(xenfb, down, xk2linux[keycode]) < 0) + fprintf(stderr, "Key %d %s lost (%s)\n", + xk2linux[keycode], down ? "down" : "up", + strerror(errno)); +} + +static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl) +{ + /* initial pointer state: at (0,0), buttons up */ + static int last_x, last_y, last_button; + rfbScreenInfoPtr server = cl->screen; + struct xenfb *xenfb = server->screenData; + int i, last_down, down, ret; + + for (i = 0; i < 8; i++) { + last_down = last_button & (1 << i); + down = buttonMask & (1 << i); + if (down == last_down) + continue; + /* FIXME this assumes buttons are numbered the same; verify they are */ + if (xenfb_send_key(xenfb, down != 0, BTN_MOUSE + i) < 0) + fprintf(stderr, "Button %d %s lost (%s)\n", + i, down ? "down" : "up", strerror(errno)); + } + + if (x != last_x || y != last_y) { + if (xenfb->abs_pointer_wanted) + ret = xenfb_send_position(xenfb, x, y); + else + ret = xenfb_send_motion(xenfb, x - last_x, y - last_y); + if (ret < 0) + fprintf(stderr, "Pointer to %d,%d lost (%s)\n", + x, y, strerror(errno)); + } + + last_button = buttonMask; + last_x = x; + last_y = y; +} + +static void xenstore_write_vncport(int port, int domid) +{ + char *buf = NULL, *path; + char portstr[10]; + struct xs_handle *xsh = NULL; + + xsh = xs_daemon_open(); + if (xsh == NULL) + return; + + path = xs_get_domain_path(xsh, domid); + if (path == NULL) { + fprintf(stderr, "Can't get domain path (%s)\n", + strerror(errno)); + goto out; + } + + if (asprintf(&buf, "%s/console/vnc-port", path) == -1) { + fprintf(stderr, "Can't make vncport path\n"); + goto out; + } + + if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) { + fprintf(stderr, "Can't make vncport value\n"); + goto out; + } + + if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr))) + fprintf(stderr, "Can't set vncport (%s)\n", + strerror(errno)); + + out: + free(buf); +} + + +static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h) +{ + rfbScreenInfoPtr server = xenfb->user_data; + rfbMarkRectAsModified(server, x, y, x + w, y + h); +} + +static struct option options[] = { + { "domid", 1, NULL, 'd' }, + { "vncport", 1, NULL, 'p' }, + { "title", 1, NULL, 't' }, + { "unused", 0, NULL, 'u' }, + { "listen", 1, NULL, 'l' }, +}; + +int main(int argc, char **argv) +{ + rfbScreenInfoPtr server; + char *fake_argv[7] = { "vncfb", "-rfbport", "5901", + "-desktop", "xen-vncfb", + "-listen", "127.0.0.1" }; + int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]); + int domid = -1, port = -1; + char *title = NULL; + char *listen = NULL; + bool unused = false; + int opt; + struct xenfb *xenfb; + fd_set readfds; + int nfds; + char portstr[10]; + char *endp; + + while ((opt = getopt_long(argc, argv, "d:p:t:u", options, + NULL)) != -1) { + switch (opt) { + case 'd': + errno = 0; + domid = strtol(optarg, &endp, 10); + if (endp == optarg || *endp || errno) { + fprintf(stderr, "Invalid domain id specified\n"); + exit(1); + } + break; + case 'p': + errno = 0; + port = strtol(optarg, &endp, 10); + if (endp == optarg || *endp || errno) { + fprintf(stderr, "Invalid port specified\n"); + exit(1); + } + break; + case 't': + title = strdup(optarg); + break; + case 'u': + unused = true; + break; + case 'l': + listen = strdup(optarg); + break; + } + } + if (optind != argc) { + fprintf(stderr, "Invalid options!\n"); + exit(1); + } + if (domid <= 0) { + fprintf(stderr, "Domain ID must be specified!\n"); + exit(1); + } + + if (port <= 0) + port = 5900 + domid; + if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) { + fprintf(stderr, "Invalid port specified\n"); + exit(1); + } + + fake_argv[2] = portstr; + + if (title != NULL) + fake_argv[4] = title; + + if (listen != NULL) + fake_argv[6] = listen; + + signal(SIGPIPE, SIG_IGN); + + xenfb = xenfb_new(); + if (xenfb == NULL) { + fprintf(stderr, "Could not create framebuffer (%s)\n", + strerror(errno)); + exit(1); + } + + if (xenfb_attach_dom(xenfb, domid) < 0) { + fprintf(stderr, "Could not connect to domain (%s)\n", + strerror(errno)); + exit(1); + } + + server = rfbGetScreen(&fake_argc, fake_argv, + xenfb->width, xenfb->height, + 8, 3, xenfb->depth / 8); + if (server == NULL) { + fprintf(stderr, "Could not create VNC server\n"); + exit(1); + } + + xenfb->user_data = server; + xenfb->update = vnc_update; + + if (unused) + server->autoPort = true; + + server->serverFormat.redShift = 16; + server->serverFormat.greenShift = 8; + server->serverFormat.blueShift = 0; + server->kbdAddEvent = on_kbd_event; + server->ptrAddEvent = on_ptr_event; + server->frameBuffer = xenfb->pixels; + server->screenData = xenfb; + server->cursor = NULL; + rfbInitServer(server); + + rfbRunEventLoop(server, -1, true); + + xenstore_write_vncport(server->port, domid); + + for (;;) { + FD_ZERO(&readfds); + nfds = xenfb_select_fds(xenfb, &readfds); + + if (select(nfds, &readfds, NULL, NULL, NULL) < 0) { + if (errno == EINTR) + continue; + fprintf(stderr, + "Can't select() on event channel (%s)\n", + strerror(errno)); + break; + } + + xenfb_poll(xenfb, &readfds); + } + + rfbScreenCleanup(server); + xenfb_delete(xenfb); + + return 0; +} diff --git a/tools/xenfb/xenfb.c b/tools/xenfb/xenfb.c new file mode 100644 index 0000000000..82d31772df --- /dev/null +++ b/tools/xenfb/xenfb.c @@ -0,0 +1,691 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xenfb.h" + +// FIXME defend against malicious frontend? + +struct xenfb_device { + const char *devicetype; + char nodename[64]; /* backend xenstore dir */ + char otherend[64]; /* frontend xenstore dir */ + int otherend_id; /* frontend domid */ + enum xenbus_state state; /* backend state */ + void *page; /* shared page */ + evtchn_port_t port; + struct xenfb_private *xenfb; +}; + +struct xenfb_private { + struct xenfb pub; + int evt_xch; /* event channel driver handle */ + int xc; /* hypervisor interface handle */ + struct xs_handle *xsh; /* xs daemon handle */ + struct xenfb_device fb, kbd; + size_t fb_len; /* size of framebuffer */ +}; + +static void xenfb_detach_dom(struct xenfb_private *); + +static char *xenfb_path_in_dom(struct xs_handle *xsh, + char *buf, size_t size, + unsigned domid, const char *fmt, ...) +{ + va_list ap; + char *domp = xs_get_domain_path(xsh, domid); + int n; + + if (domp == NULL) + return NULL; + + n = snprintf(buf, size, "%s/", domp); + free(domp); + if (n >= size) + return NULL; + + va_start(ap, fmt); + n += vsnprintf(buf + n, size - n, fmt, ap); + va_end(ap); + if (n >= size) + return NULL; + + return buf; +} + +static int xenfb_xs_scanf1(struct xs_handle *xsh, + const char *dir, const char *node, + const char *fmt, void *dest) +{ + char buf[1024]; + char *p; + int ret; + + if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) { + errno = ENOENT; + return -1; + } + p = xs_read(xsh, XBT_NULL, buf, NULL); + if (!p) { + errno = ENOENT; + return -1; + } + ret = sscanf(p, fmt, dest); + free(p); + if (ret != 1) { + errno = EDOM; + return -1; + } + return ret; +} + +static int xenfb_xs_printf(struct xs_handle *xsh, + const char *dir, const char *node, char *fmt, ...) +{ + va_list ap; + char key[1024]; + char val[1024]; + int n; + + if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) { + errno = ENOENT; + return -1; + } + + va_start(ap, fmt); + n = vsnprintf(val, sizeof(val), fmt, ap); + va_end(ap); + if (n >= sizeof(val)) { + errno = ENOSPC; /* close enough */ + return -1; + } + + if (!xs_write(xsh, XBT_NULL, key, val, n)) + return -1; + return 0; +} + +static void xenfb_device_init(struct xenfb_device *dev, + const char *type, + struct xenfb_private *xenfb) +{ + dev->devicetype = type; + dev->otherend_id = -1; + dev->port = -1; + dev->xenfb = xenfb; +} + +int xenfb_device_set_domain(struct xenfb_device *dev, int domid) +{ + struct xenfb_private *xenfb = dev->xenfb; + + dev->otherend_id = domid; + + if (!xenfb_path_in_dom(xenfb->xsh, + dev->otherend, sizeof(dev->otherend), + domid, "device/%s/0", dev->devicetype)) { + errno = ENOENT; + return -1; + } + if (!xenfb_path_in_dom(xenfb->xsh, + dev->nodename, sizeof(dev->nodename), + 0, "backend/%s/%d/0", dev->devicetype, domid)) { + errno = ENOENT; + return -1; + } + + return 0; +} + +struct xenfb *xenfb_new(void) +{ + struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); + int serrno; + + if (xenfb == NULL) + return NULL; + + memset(xenfb, 0, sizeof(*xenfb)); + xenfb->evt_xch = xenfb->xc = -1; + xenfb_device_init(&xenfb->fb, "vfb", xenfb); + xenfb_device_init(&xenfb->kbd, "vkbd", xenfb); + + xenfb->evt_xch = xc_evtchn_open(); + if (xenfb->evt_xch == -1) + goto fail; + + xenfb->xc = xc_interface_open(); + if (xenfb->xc == -1) + goto fail; + + xenfb->xsh = xs_daemon_open(); + if (!xenfb->xsh) + goto fail; + + return &xenfb->pub; + + fail: + serrno = errno; + xenfb_delete(&xenfb->pub); + errno = serrno; + return NULL; +} + +void xenfb_delete(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + + xenfb_detach_dom(xenfb); + if (xenfb->xc >= 0) + xc_interface_close(xenfb->xc); + if (xenfb->evt_xch >= 0) + xc_evtchn_close(xenfb->evt_xch); + if (xenfb->xsh) + xs_daemon_close(xenfb->xsh); + free(xenfb); +} + +static enum xenbus_state xenfb_read_state(struct xs_handle *xsh, + const char *dir) +{ + int ret, state; + + ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state); + if (ret < 0) + return XenbusStateUnknown; + + if ((unsigned)state > XenbusStateClosed) + state = XenbusStateUnknown; + return state; +} + +static int xenfb_switch_state(struct xenfb_device *dev, + enum xenbus_state state) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + + if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0) + return -1; + dev->state = state; + return 0; +} + +static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir, + unsigned awaited) +{ + unsigned state, dummy; + char **vec; + + for (;;) { + state = xenfb_read_state(xsh, dir); + if (state < 0) + return -1; + + if ((1 << state) & awaited) + return state; + + vec = xs_read_watch(xsh, &dummy); + if (!vec) + return -1; + free(vec); + } +} + +static int xenfb_wait_for_backend_creation(struct xenfb_device *dev) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + int state; + + if (!xs_watch(xsh, dev->nodename, "")) + return -1; + state = xenfb_wait_for_state(xsh, dev->nodename, + (1 << XenbusStateInitialising) + | (1 << XenbusStateClosed) +#if 1 /* TODO fudging state to permit restarting; to be removed */ + | (1 << XenbusStateInitWait) + | (1 << XenbusStateConnected) + | (1 << XenbusStateClosing) +#endif + ); + xs_unwatch(xsh, dev->nodename, ""); + + switch (state) { +#if 1 + case XenbusStateInitWait: + case XenbusStateConnected: + printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */ +#endif + case XenbusStateInitialising: + case XenbusStateClosing: + case XenbusStateClosed: + break; + default: + return -1; + } + + return 0; +} + +static int xenfb_hotplug(struct xenfb_device *dev) +{ + if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, + "hotplug-status", "connected")) + return -1; + return 0; +} + +static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev) +{ + switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, +#if 1 /* TODO fudging state to permit restarting; to be removed */ + (1 << XenbusStateInitialised) + | (1 << XenbusStateConnected) +#else + 1 << XenbusStateInitialised, +#endif + )) { +#if 1 + case XenbusStateConnected: + printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */ +#endif + case XenbusStateInitialised: + break; + default: + return -1; + } + + return 0; +} + +static int xenfb_map_fb(struct xenfb_private *xenfb, int domid) +{ + struct xenfb_page *page = xenfb->fb.page; + int n_fbmfns; + int n_fbdirs; + unsigned long *fbmfns; + + n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + n_fbdirs = n_fbmfns * sizeof(unsigned long); + n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE; + + /* + * Bug alert: xc_map_foreign_batch() can fail partly and + * return a non-null value. This is a design flaw. When it + * happens, we happily continue here, and later crash on + * access. + */ + fbmfns = xc_map_foreign_batch(xenfb->xc, domid, + PROT_READ, page->pd, n_fbdirs); + if (fbmfns == NULL) + return -1; + + xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid, + PROT_READ | PROT_WRITE, fbmfns, n_fbmfns); + if (xenfb->pub.pixels == NULL) { + munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE); + return -1; + } + + return munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE); +} + +static int xenfb_bind(struct xenfb_device *dev) +{ + struct xenfb_private *xenfb = dev->xenfb; + unsigned long mfn; + evtchn_port_t evtchn; + + if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu", + &mfn) < 0) + return -1; + if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u", + &evtchn) < 0) + return -1; + + dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch, + dev->otherend_id, evtchn); + if (dev->port == -1) + return -1; + + dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id, + XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); + if (dev->page == NULL) + return -1; + + return 0; +} + +static void xenfb_unbind(struct xenfb_device *dev) +{ + if (dev->page) { + munmap(dev->page, XC_PAGE_SIZE); + dev->page = NULL; + } + if (dev->port >= 0) { + xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port); + dev->port = -1; + } +} + +static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev) +{ + switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend, + 1 << XenbusStateConnected)) { + case XenbusStateConnected: + break; + default: + return -1; + } + + return 0; +} + +static void xenfb_dev_fatal(struct xenfb_device *dev, int err, + const char *fmt, ...) +{ + struct xs_handle *xsh = dev->xenfb->xsh; + va_list ap; + char errdir[80]; + char buf[1024]; + int n; + + fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + if (err) + fprintf(stderr, " (%s)", strerror(err)); + putc('\n', stderr); + + if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0, + "error/%s", dev->nodename)) + goto out; /* FIXME complain */ + + va_start(ap, fmt); + n = snprintf(buf, sizeof(buf), "%d ", err); + snprintf(buf + n, sizeof(buf) - n, fmt, ap); + va_end(ap); + + if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0) + goto out; /* FIXME complain */ + + out: + xenfb_switch_state(dev, XenbusStateClosing); +} + +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + struct xs_handle *xsh = xenfb->xsh; + int val, serrno; + struct xenfb_page *fb_page; + + xenfb_detach_dom(xenfb); + + xenfb_device_set_domain(&xenfb->fb, domid); + xenfb_device_set_domain(&xenfb->kbd, domid); + + if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1")) + goto error; + if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait)) + goto error; + + if (xenfb_hotplug(&xenfb->fb) < 0) + goto error; + if (xenfb_hotplug(&xenfb->kbd) < 0) + goto error; + + if (!xs_watch(xsh, xenfb->fb.otherend, "")) + goto error; + if (!xs_watch(xsh, xenfb->kbd.otherend, "")) + goto error; + + if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0) + goto error; + if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0) + goto error; + + if (xenfb_bind(&xenfb->fb) < 0) + goto error; + if (xenfb_bind(&xenfb->kbd) < 0) + goto error; + + if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update", + "%d", &val) < 0) + val = 0; + if (!val) { + errno = ENOTSUP; + goto error; + } + xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1"); + + /* TODO check for permitted ranges */ + fb_page = xenfb->fb.page; + xenfb->pub.depth = fb_page->depth; + xenfb->pub.width = fb_page->width; + xenfb->pub.height = fb_page->height; + /* TODO check for consistency with the above */ + xenfb->fb_len = fb_page->mem_length; + xenfb->pub.row_stride = fb_page->line_length; + + if (xenfb_map_fb(xenfb, domid) < 0) + goto error; + + if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected)) + goto error; + if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected)) + goto error; + + if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0) + goto error; + if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer", + "%d", &val) < 0) + val = 0; + xenfb->pub.abs_pointer_wanted = val; + + return 0; + + error: + serrno = errno; + xenfb_detach_dom(xenfb); + xenfb_dev_fatal(&xenfb->fb, serrno, "on fire"); + xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire"); + errno = serrno; + return -1; +} + +static void xenfb_detach_dom(struct xenfb_private *xenfb) +{ + xenfb_unbind(&xenfb->fb); + xenfb_unbind(&xenfb->kbd); + if (xenfb->pub.pixels) { + munmap(xenfb->pub.pixels, xenfb->fb_len); + xenfb->pub.pixels = NULL; + } +} + +static void xenfb_on_fb_event(struct xenfb_private *xenfb) +{ + uint32_t prod, cons; + struct xenfb_page *page = xenfb->fb.page; + + prod = page->out_prod; + if (prod == page->out_cons) + return; + rmb(); /* ensure we see ring contents up to prod */ + for (cons = page->out_cons; cons != prod; cons++) { + union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons); + + switch (event->type) { + case XENFB_TYPE_UPDATE: + if (xenfb->pub.update) + xenfb->pub.update(&xenfb->pub, + event->update.x, event->update.y, + event->update.width, event->update.height); + break; + } + } + mb(); /* ensure we're done with ring contents */ + page->out_cons = cons; + xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port); +} + +static void xenfb_on_kbd_event(struct xenfb_private *xenfb) +{ + struct xenkbd_page *page = xenfb->kbd.page; + + /* We don't understand any keyboard events, so just ignore them. */ + if (page->out_prod == page->out_cons) + return; + page->out_cons = page->out_prod; + xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +static void xenfb_on_state_change(struct xenfb_device *dev) +{ + enum xenbus_state state; + + state = xenfb_read_state(dev->xenfb->xsh, dev->otherend); + + switch (state) { + case XenbusStateUnknown: + case XenbusStateInitialising: + case XenbusStateInitWait: + case XenbusStateInitialised: + case XenbusStateConnected: + break; + case XenbusStateClosing: + xenfb_unbind(dev); + xenfb_switch_state(dev, state); + break; + case XenbusStateClosed: + xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); + xenfb_switch_state(dev, state); + } +} + +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + evtchn_port_t port; + unsigned dummy; + char **vec; + + if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { + port = xc_evtchn_pending(xenfb->evt_xch); + if (port == -1) + return -1; + + if (port == xenfb->fb.port) + xenfb_on_fb_event(xenfb); + else if (port == xenfb->kbd.port) + xenfb_on_kbd_event(xenfb); + + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) + return -1; + } + + if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { + vec = xs_read_watch(xenfb->xsh, &dummy); + free(vec); + xenfb_on_state_change(&xenfb->fb); + xenfb_on_state_change(&xenfb->kbd); + } + + return 0; +} + +int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + int fd1 = xc_evtchn_fd(xenfb->evt_xch); + int fd2 = xs_fileno(xenfb->xsh); + + FD_SET(fd1, readfds); + FD_SET(fd2, readfds); + return fd1 > fd2 ? fd1 + 1 : fd2 + 1; +} + +static int xenfb_kbd_event(struct xenfb_private *xenfb, + union xenkbd_in_event *event) +{ + uint32_t prod; + struct xenkbd_page *page = xenfb->kbd.page; + + if (xenfb->kbd.state != XenbusStateConnected) + return 0; + + prod = page->in_prod; + if (prod - page->in_cons == XENKBD_IN_RING_LEN) { + errno = EAGAIN; + return -1; + } + + mb(); /* ensure ring space available */ + XENKBD_IN_RING_REF(page, prod) = *event; + wmb(); /* ensure ring contents visible */ + page->in_prod = prod + 1; + return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); +} + +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_KEY; + event.key.pressed = down ? 1 : 0; + event.key.keycode = keycode; + + return xenfb_kbd_event(xenfb, &event); +} + +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_MOTION; + event.motion.rel_x = rel_x; + event.motion.rel_y = rel_y; + + return xenfb_kbd_event(xenfb, &event); +} + +int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + union xenkbd_in_event event; + + memset(&event, 0, XENKBD_IN_EVENT_SIZE); + event.type = XENKBD_TYPE_POS; + event.pos.abs_x = abs_x; + event.pos.abs_y = abs_y; + + return xenfb_kbd_event(xenfb, &event); +} diff --git a/tools/xenfb/xenfb.h b/tools/xenfb/xenfb.h new file mode 100644 index 0000000000..007eb3b9b4 --- /dev/null +++ b/tools/xenfb/xenfb.h @@ -0,0 +1,34 @@ +#ifndef _XENFB_H_ +#define _XENFB_H_ + +#include +#include + +struct xenfb +{ + void *pixels; + + int row_stride; + int depth; + int width; + int height; + int abs_pointer_wanted; + + void *user_data; + + void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); +}; + +struct xenfb *xenfb_new(void); +void xenfb_delete(struct xenfb *xenfb); + +int xenfb_attach_dom(struct xenfb *xenfb, int domid); + +int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds); +int xenfb_poll(struct xenfb *xenfb, fd_set *readfds); + +int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode); +int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y); +int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y); + +#endif diff --git a/xen/include/public/io/fbif.h b/xen/include/public/io/fbif.h new file mode 100644 index 0000000000..7b8861d51e --- /dev/null +++ b/xen/include/public/io/fbif.h @@ -0,0 +1,116 @@ +/* + * fbif.h -- Xen virtual frame buffer device + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef __XEN_PUBLIC_IO_FBIF_H__ +#define __XEN_PUBLIC_IO_FBIF_H__ + +#include + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + */ + +/* Event type 1 currently not used */ +/* + * Framebuffer update notification event + * Capable frontend sets feature-update in xenstore. + * Backend requests it by setting request-update in xenstore. + */ +#define XENFB_TYPE_UPDATE 2 + +struct xenfb_update +{ + __u8 type; /* XENFB_TYPE_UPDATE */ + __s32 x; /* source x */ + __s32 y; /* source y */ + __s32 width; /* rect width */ + __s32 height; /* rect height */ +}; + +#define XENFB_OUT_EVENT_SIZE 40 + +union xenfb_out_event +{ + __u8 type; + struct xenfb_update update; + char pad[XENFB_OUT_EVENT_SIZE]; +}; + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + * No in events currently defined. + */ + +#define XENFB_IN_EVENT_SIZE 40 + +union xenfb_in_event +{ + __u8 type; + char pad[XENFB_IN_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENFB_IN_RING_SIZE 1024 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) +#define XENFB_IN_RING_OFFS 1024 +#define XENFB_IN_RING(page) \ + ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) +#define XENFB_IN_RING_REF(page, idx) \ + (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) + +#define XENFB_OUT_RING_SIZE 2048 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) +#define XENFB_OUT_RING(page) \ + ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) +#define XENFB_OUT_RING_REF(page, idx) \ + (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) + +struct xenfb_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; + + __s32 width; /* the width of the framebuffer (in pixels) */ + __s32 height; /* the height of the framebuffer (in pixels) */ + __u32 line_length; /* the length of a row of pixels (in bytes) */ + __u32 mem_length; /* the length of the framebuffer (in bytes) */ + __u8 depth; /* the depth of a pixel (in bits) */ + + /* + * Framebuffer page directory + * + * Each directory page holds PAGE_SIZE / sizeof(*pd) + * framebuffer pages, and can thus map up to PAGE_SIZE * + * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and + * sizeof(unsigned long) == 4, that's 4 Megs. Two directory + * pages should be enough for a while. + */ + unsigned long pd[2]; +}; + +/* + * Wart: xenkbd needs to know resolution. Put it here until a better + * solution is found, but don't leak it to the backend. + */ +#ifdef __KERNEL__ +#define XENFB_WIDTH 800 +#define XENFB_HEIGHT 600 +#define XENFB_DEPTH 32 +#endif + +#endif diff --git a/xen/include/public/io/kbdif.h b/xen/include/public/io/kbdif.h new file mode 100644 index 0000000000..be8c91545a --- /dev/null +++ b/xen/include/public/io/kbdif.h @@ -0,0 +1,108 @@ +/* + * kbdif.h -- Xen virtual keyboard/mouse + * + * Copyright (C) 2005 Anthony Liguori + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef __XEN_PUBLIC_IO_KBDIF_H__ +#define __XEN_PUBLIC_IO_KBDIF_H__ + +#include + +/* In events (backend -> frontend) */ + +/* + * Frontends should ignore unknown in events. + */ + +/* Pointer movement event */ +#define XENKBD_TYPE_MOTION 1 +/* Event type 2 currently not used */ +/* Key event (includes pointer buttons) */ +#define XENKBD_TYPE_KEY 3 +/* + * Pointer position event + * Capable backend sets feature-abs-pointer in xenstore. + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting + * request-abs-update in xenstore. + */ +#define XENKBD_TYPE_POS 4 + +struct xenkbd_motion +{ + __u8 type; /* XENKBD_TYPE_MOTION */ + __s32 rel_x; /* relative X motion */ + __s32 rel_y; /* relative Y motion */ +}; + +struct xenkbd_key +{ + __u8 type; /* XENKBD_TYPE_KEY */ + __u8 pressed; /* 1 if pressed; 0 otherwise */ + __u32 keycode; /* KEY_* from linux/input.h */ +}; + +struct xenkbd_position +{ + __u8 type; /* XENKBD_TYPE_POS */ + __s32 abs_x; /* absolute X position (in FB pixels) */ + __s32 abs_y; /* absolute Y position (in FB pixels) */ +}; + +#define XENKBD_IN_EVENT_SIZE 40 + +union xenkbd_in_event +{ + __u8 type; + struct xenkbd_motion motion; + struct xenkbd_key key; + struct xenkbd_position pos; + char pad[XENKBD_IN_EVENT_SIZE]; +}; + +/* Out events (frontend -> backend) */ + +/* + * Out events may be sent only when requested by backend, and receipt + * of an unknown out event is an error. + * No out events currently defined. + */ + +#define XENKBD_OUT_EVENT_SIZE 40 + +union xenkbd_out_event +{ + __u8 type; + char pad[XENKBD_OUT_EVENT_SIZE]; +}; + +/* shared page */ + +#define XENKBD_IN_RING_SIZE 2048 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) +#define XENKBD_IN_RING_OFFS 1024 +#define XENKBD_IN_RING(page) \ + ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) +#define XENKBD_IN_RING_REF(page, idx) \ + (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) + +#define XENKBD_OUT_RING_SIZE 1024 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) +#define XENKBD_OUT_RING(page) \ + ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) +#define XENKBD_OUT_RING_REF(page, idx) \ + (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) + +struct xenkbd_page +{ + __u32 in_cons, in_prod; + __u32 out_cons, out_prod; +}; + +#endif From f5bf5c912030f39d802f972c13b23e4afcf6a49b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 09:51:13 +0000 Subject: [PATCH 119/282] [HVM][VMX] Rename io.c -> intr.c. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vmx/Makefile | 2 +- xen/arch/x86/hvm/vmx/{io.c => intr.c} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename xen/arch/x86/hvm/vmx/{io.c => intr.c} (100%) diff --git a/xen/arch/x86/hvm/vmx/Makefile b/xen/arch/x86/hvm/vmx/Makefile index 3eede43031..ba31793c2f 100644 --- a/xen/arch/x86/hvm/vmx/Makefile +++ b/xen/arch/x86/hvm/vmx/Makefile @@ -1,6 +1,6 @@ subdir-$(x86_32) += x86_32 subdir-$(x86_64) += x86_64 -obj-y += io.o +obj-y += intr.o obj-y += vmcs.o obj-y += vmx.o diff --git a/xen/arch/x86/hvm/vmx/io.c b/xen/arch/x86/hvm/vmx/intr.c similarity index 100% rename from xen/arch/x86/hvm/vmx/io.c rename to xen/arch/x86/hvm/vmx/intr.c From fefaf21f9d1376009766e62424d76bc112f320e6 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 09:59:56 +0000 Subject: [PATCH 120/282] [XENOPROF] Fix oprofile for AMD SVM guests. Signed-off-by: Keir Fraser --- xen/arch/x86/oprofile/op_model_athlon.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/oprofile/op_model_athlon.c b/xen/arch/x86/oprofile/op_model_athlon.c index 1d8f9668f4..ec99be48b0 100644 --- a/xen/arch/x86/oprofile/op_model_athlon.c +++ b/xen/arch/x86/oprofile/op_model_athlon.c @@ -113,14 +113,15 @@ static int athlon_check_ctrs(unsigned int const cpu, unsigned long eip = regs->eip; int mode = 0; struct vcpu *v = current; - struct cpu_user_regs tmp_regs; + struct cpu_user_regs *guest_regs = guest_cpu_user_regs(); if (!guest_mode(regs) && (regs->eip == (unsigned long)svm_stgi_label)) { /* SVM guest was running when NMI occurred */ - hvm_store_cpu_guest_regs(v, &tmp_regs, NULL); - eip = tmp_regs.eip; - mode = xenoprofile_get_mode(v, &tmp_regs); + ASSERT(is_hvm_vcpu(v)); + hvm_store_cpu_guest_regs(v, guest_regs, NULL); + eip = guest_regs->eip; + mode = xenoprofile_get_mode(v, guest_regs); } else { eip = regs->eip; mode = xenoprofile_get_mode(v, regs); From 515db7a43abd0a872878c7408c1eb136e299d9fa Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 10:47:57 +0000 Subject: [PATCH 121/282] [XEND] Fix missing serial and localtime args in device model for HVM Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 3d79c657c9..3bb0ba4cd9 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -186,19 +186,21 @@ LEGACY_IMAGE_HVM_CFG = [ ('pae', int), ('apic', int), ('acpi', int), - ('serial', str), ] LEGACY_IMAGE_HVM_DEVICES_CFG = [ + ('acpi', int), ('boot', str), ('fda', str), ('fdb', str), - ('soundhw', str), ('isa', str), - ('vcpus', int), - ('acpi', int), + ('keymap', str), + ('localtime', str), + ('serial', str), + ('soundhw', str), ('usb', str), - ('usbdevice', str), + ('usbdevice', str), + ('vcpus', int), ] From e4022aef8e9076a5ffe70abfd2fff6fee5c99512 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 11:04:27 +0000 Subject: [PATCH 122/282] [HVM] Add canonical address checks and generally clean up. Based on a patch from Jan Beulich Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/svm/emulate.c | 11 --- xen/arch/x86/hvm/svm/svm.c | 122 ++++++++++++++--------- xen/arch/x86/hvm/vmx/vmx.c | 154 ++++++++++++++++++------------ xen/arch/x86/mm/shadow/common.c | 11 ++- xen/include/asm-x86/hvm/hvm.h | 4 + xen/include/asm-x86/x86_32/page.h | 2 + xen/include/asm-x86/x86_64/page.h | 2 + 7 files changed, 187 insertions(+), 119 deletions(-) diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c index c0ea001c82..7966bb9da2 100644 --- a/xen/arch/x86/hvm/svm/emulate.c +++ b/xen/arch/x86/hvm/svm/emulate.c @@ -128,17 +128,6 @@ static inline unsigned long DECODE_GPR_VALUE(struct vmcb_struct *vmcb, return (unsigned long) -1; \ } -#if 0 -/* - * hv_is_canonical - checks if the given address is canonical - */ -static inline u64 hv_is_canonical(u64 addr) -{ - u64 bits = addr & (u64)0xffff800000000000; - return (u64)((bits == (u64)0xffff800000000000) || (bits == (u64)0x0)); -} -#endif - #define modrm operand [0] #define sib operand [1] diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 9c5393f5f5..b95be55b80 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -269,13 +269,11 @@ static int svm_long_mode_enabled(struct vcpu *v) return test_bit(SVM_CPU_STATE_LMA_ENABLED, &v->arch.hvm_svm.cpu_state); } -#define IS_CANO_ADDRESS(add) 1 - static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) { u64 msr_content = 0; - struct vcpu *vc = current; - struct vmcb_struct *vmcb = vc->arch.hvm_svm.vmcb; + struct vcpu *v = current; + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; switch ((u32)regs->ecx) { @@ -284,17 +282,25 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) msr_content &= ~EFER_SVME; break; +#ifdef __x86_64__ case MSR_FS_BASE: msr_content = vmcb->fs.base; - break; + goto check_long_mode; case MSR_GS_BASE: msr_content = vmcb->gs.base; - break; + goto check_long_mode; case MSR_SHADOW_GS_BASE: msr_content = vmcb->kerngsbase; + check_long_mode: + if ( !svm_long_mode_enabled(v) ) + { + svm_inject_exception(v, TRAP_gp_fault, 1, 0); + return 0; + } break; +#endif case MSR_STAR: msr_content = vmcb->star; @@ -326,25 +332,25 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) { u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32); + u32 ecx = regs->ecx; struct vcpu *v = current; struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; HVM_DBG_LOG(DBG_LEVEL_1, "msr %x msr_content %"PRIx64"\n", - (u32)regs->ecx, msr_content); + ecx, msr_content); - switch ( (u32)regs->ecx ) + switch ( ecx ) { case MSR_EFER: -#ifdef __x86_64__ /* offending reserved bit will cause #GP */ if ( msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE) ) { - printk("Trying to set reserved bit in EFER: %"PRIx64"\n", - msr_content); - svm_inject_exception(v, TRAP_gp_fault, 1, 0); - return 0; + gdprintk(XENLOG_WARNING, "Trying to set reserved bit in " + "EFER: %"PRIx64"\n", msr_content); + goto gp_fault; } +#ifdef __x86_64__ /* LME: 0 -> 1 */ if ( msr_content & EFER_LME && !test_bit(SVM_CPU_STATE_LME_ENABLED, &v->arch.hvm_svm.cpu_state)) @@ -353,10 +359,9 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) !test_bit(SVM_CPU_STATE_PAE_ENABLED, &v->arch.hvm_svm.cpu_state) ) { - printk("Trying to set LME bit when " - "in paging mode or PAE bit is not set\n"); - svm_inject_exception(v, TRAP_gp_fault, 1, 0); - return 0; + gdprintk(XENLOG_WARNING, "Trying to set LME bit when " + "in paging mode or PAE bit is not set\n"); + goto gp_fault; } set_bit(SVM_CPU_STATE_LME_ENABLED, &v->arch.hvm_svm.cpu_state); } @@ -371,37 +376,38 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) vmcb->efer = msr_content | EFER_SVME; break; +#ifdef __x86_64__ case MSR_FS_BASE: case MSR_GS_BASE: - if ( !svm_long_mode_enabled(v) ) - goto exit_and_crash; - - if (!IS_CANO_ADDRESS(msr_content)) - { - HVM_DBG_LOG(DBG_LEVEL_1, "Not cano address of msr write\n"); - svm_inject_exception(v, TRAP_gp_fault, 1, 0); - } - - if (regs->ecx == MSR_FS_BASE) - vmcb->fs.base = msr_content; - else - vmcb->gs.base = msr_content; - break; - case MSR_SHADOW_GS_BASE: - vmcb->kerngsbase = msr_content; + if ( !svm_long_mode_enabled(v) ) + goto gp_fault; + + if ( !is_canonical_address(msr_content) ) + goto uncanonical_address; + + if ( ecx == MSR_FS_BASE ) + vmcb->fs.base = msr_content; + else if ( ecx == MSR_GS_BASE ) + vmcb->gs.base = msr_content; + else + vmcb->kerngsbase = msr_content; break; +#endif case MSR_STAR: vmcb->star = msr_content; break; case MSR_LSTAR: - vmcb->lstar = msr_content; - break; - case MSR_CSTAR: - vmcb->cstar = msr_content; + if ( !is_canonical_address(msr_content) ) + goto uncanonical_address; + + if ( ecx == MSR_LSTAR ) + vmcb->lstar = msr_content; + else + vmcb->cstar = msr_content; break; case MSR_SYSCALL_MASK: @@ -414,10 +420,11 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) return 1; - exit_and_crash: - gdprintk(XENLOG_ERR, "Fatal error writing MSR %lx\n", (long)regs->ecx); - domain_crash(v->domain); - return 1; /* handled */ + uncanonical_address: + HVM_DBG_LOG(DBG_LEVEL_1, "Not cano address of msr write %x\n", ecx); + gp_fault: + svm_inject_exception(v, TRAP_gp_fault, 1, 0); + return 0; } @@ -1272,7 +1279,7 @@ static inline int svm_get_io_address( #endif /* d field of cs.attr is 1 for 32-bit, 0 for 16 or 64 bit. - * l field combined with EFER_LMA -> longmode says whether it's 16 or 64 bit. + * l field combined with EFER_LMA says whether it's 16 or 64 bit. */ asize = (long_mode)?64:((vmcb->cs.attr.fields.db)?32:16); @@ -1383,8 +1390,35 @@ static inline int svm_get_io_address( *addr += seg->base; } - else if (seg == &vmcb->fs || seg == &vmcb->gs) - *addr += seg->base; +#ifdef __x86_64__ + else + { + if (seg == &vmcb->fs || seg == &vmcb->gs) + *addr += seg->base; + + if (!is_canonical_address(*addr) || + !is_canonical_address(*addr + size - 1)) + { + svm_inject_exception(v, TRAP_gp_fault, 1, 0); + return 0; + } + if (*count > (1UL << 48) / size) + *count = (1UL << 48) / size; + if (!(regs->eflags & EF_DF)) + { + if (*addr + *count * size - 1 < *addr || + !is_canonical_address(*addr + *count * size - 1)) + *count = (*addr & ~((1UL << 48) - 1)) / size; + } + else + { + if ((*count - 1) * size > *addr || + !is_canonical_address(*addr + (*count - 1) * size)) + *count = (*addr & ~((1UL << 48) - 1)) / size + 1; + } + ASSERT(*count); + } +#endif return 1; } diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 58cca4bea4..556ea7b79f 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -95,13 +95,7 @@ static void vmx_save_host_msrs(void) rdmsrl(msr_index[i], host_msr_state->msrs[i]); } -#define CASE_READ_MSR(address) \ - case MSR_ ## address: \ - msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_ ## address]; \ - break - -#define CASE_WRITE_MSR(address) \ - case MSR_ ## address: \ +#define WRITE_MSR(address) \ guest_msr_state->msrs[VMX_INDEX_MSR_ ## address] = msr_content; \ if ( !test_bit(VMX_INDEX_MSR_ ## address, &guest_msr_state->flags) )\ set_bit(VMX_INDEX_MSR_ ## address, &guest_msr_state->flags); \ @@ -109,7 +103,6 @@ static void vmx_save_host_msrs(void) set_bit(VMX_INDEX_MSR_ ## address, &host_msr_state->flags); \ break -#define IS_CANO_ADDRESS(add) 1 static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) { u64 msr_content = 0; @@ -123,27 +116,38 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) break; case MSR_FS_BASE: - if ( !(vmx_long_mode_enabled(v)) ) - goto exit_and_crash; - msr_content = __vmread(GUEST_FS_BASE); - break; + goto check_long_mode; case MSR_GS_BASE: - if ( !(vmx_long_mode_enabled(v)) ) - goto exit_and_crash; - msr_content = __vmread(GUEST_GS_BASE); - break; + goto check_long_mode; case MSR_SHADOW_GS_BASE: msr_content = guest_msr_state->shadow_gs; + check_long_mode: + if ( !(vmx_long_mode_enabled(v)) ) + { + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); + return 0; + } break; - CASE_READ_MSR(STAR); - CASE_READ_MSR(LSTAR); - CASE_READ_MSR(CSTAR); - CASE_READ_MSR(SYSCALL_MASK); + case MSR_STAR: + msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_STAR]; + break; + + case MSR_LSTAR: + msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_LSTAR]; + break; + + case MSR_CSTAR: + msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_CSTAR]; + break; + + case MSR_SYSCALL_MASK: + msr_content = guest_msr_state->msrs[VMX_INDEX_MSR_SYSCALL_MASK]; + break; default: return 0; @@ -155,32 +159,28 @@ static inline int long_mode_do_msr_read(struct cpu_user_regs *regs) regs->edx = (u32)(msr_content >> 32); return 1; - - exit_and_crash: - gdprintk(XENLOG_ERR, "Fatal error reading MSR %lx\n", (long)regs->ecx); - domain_crash(v->domain); - return 1; /* handled */ } static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) { u64 msr_content = (u32)regs->eax | ((u64)regs->edx << 32); + u32 ecx = regs->ecx; struct vcpu *v = current; struct vmx_msr_state *guest_msr_state = &v->arch.hvm_vmx.msr_state; struct vmx_msr_state *host_msr_state = &this_cpu(host_msr_state); HVM_DBG_LOG(DBG_LEVEL_1, "msr 0x%x msr_content 0x%"PRIx64"\n", - (u32)regs->ecx, msr_content); + ecx, msr_content); - switch ( (u32)regs->ecx ) { + switch ( ecx ) + { case MSR_EFER: /* offending reserved bit will cause #GP */ if ( msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE) ) { - printk("Trying to set reserved bit in EFER: %"PRIx64"\n", - msr_content); - vmx_inject_hw_exception(v, TRAP_gp_fault, 0); - return 0; + gdprintk(XENLOG_WARNING, "Trying to set reserved bit in " + "EFER: %"PRIx64"\n", msr_content); + goto gp_fault; } if ( (msr_content & EFER_LME) @@ -188,9 +188,9 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) { if ( unlikely(vmx_paging_enabled(v)) ) { - printk("Trying to set EFER.LME with paging enabled\n"); - vmx_inject_hw_exception(v, TRAP_gp_fault, 0); - return 0; + gdprintk(XENLOG_WARNING, + "Trying to set EFER.LME with paging enabled\n"); + goto gp_fault; } } else if ( !(msr_content & EFER_LME) @@ -198,9 +198,9 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) { if ( unlikely(vmx_paging_enabled(v)) ) { - printk("Trying to clear EFER.LME with paging enabled\n"); - vmx_inject_hw_exception(v, TRAP_gp_fault, 0); - return 0; + gdprintk(XENLOG_WARNING, + "Trying to clear EFER.LME with paging enabled\n"); + goto gp_fault; } } @@ -209,35 +209,40 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) case MSR_FS_BASE: case MSR_GS_BASE: + case MSR_SHADOW_GS_BASE: if ( !vmx_long_mode_enabled(v) ) - goto exit_and_crash; + goto gp_fault; - if ( !IS_CANO_ADDRESS(msr_content) ) + if ( !is_canonical_address(msr_content) ) + goto uncanonical_address; + + if ( ecx == MSR_FS_BASE ) + __vmwrite(GUEST_FS_BASE, msr_content); + else if ( ecx == MSR_GS_BASE ) + __vmwrite(GUEST_GS_BASE, msr_content); + else { - HVM_DBG_LOG(DBG_LEVEL_1, "Not cano address of msr write\n"); - vmx_inject_hw_exception(v, TRAP_gp_fault, 0); - return 0; + v->arch.hvm_vmx.msr_state.shadow_gs = msr_content; + wrmsrl(MSR_SHADOW_GS_BASE, msr_content); } - if ( regs->ecx == MSR_FS_BASE ) - __vmwrite(GUEST_FS_BASE, msr_content); - else - __vmwrite(GUEST_GS_BASE, msr_content); - break; - case MSR_SHADOW_GS_BASE: - if ( !(vmx_long_mode_enabled(v)) ) - goto exit_and_crash; + case MSR_STAR: + WRITE_MSR(STAR); - v->arch.hvm_vmx.msr_state.shadow_gs = msr_content; - wrmsrl(MSR_SHADOW_GS_BASE, msr_content); - break; + case MSR_LSTAR: + if ( !is_canonical_address(msr_content) ) + goto uncanonical_address; + WRITE_MSR(LSTAR); - CASE_WRITE_MSR(STAR); - CASE_WRITE_MSR(LSTAR); - CASE_WRITE_MSR(CSTAR); - CASE_WRITE_MSR(SYSCALL_MASK); + case MSR_CSTAR: + if ( !is_canonical_address(msr_content) ) + goto uncanonical_address; + WRITE_MSR(CSTAR); + + case MSR_SYSCALL_MASK: + WRITE_MSR(SYSCALL_MASK); default: return 0; @@ -245,10 +250,11 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) return 1; - exit_and_crash: - gdprintk(XENLOG_ERR, "Fatal error writing MSR %lx\n", (long)regs->ecx); - domain_crash(v->domain); - return 1; /* handled */ + uncanonical_address: + HVM_DBG_LOG(DBG_LEVEL_1, "Not cano address of msr write %x\n", ecx); + gp_fault: + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); + return 0; } /* @@ -1283,6 +1289,32 @@ static void vmx_io_instruction(unsigned long exit_qualification, ASSERT(count); } } +#ifdef __x86_64__ + else + { + if ( !is_canonical_address(addr) || + !is_canonical_address(addr + size - 1) ) + { + vmx_inject_hw_exception(current, TRAP_gp_fault, 0); + return; + } + if ( count > (1UL << 48) / size ) + count = (1UL << 48) / size; + if ( !(regs->eflags & EF_DF) ) + { + if ( addr + count * size - 1 < addr || + !is_canonical_address(addr + count * size - 1) ) + count = (addr & ~((1UL << 48) - 1)) / size; + } + else + { + if ( (count - 1) * size > addr || + !is_canonical_address(addr + (count - 1) * size) ) + count = (addr & ~((1UL << 48) - 1)) / size + 1; + } + ASSERT(count); + } +#endif /* * Handle string pio instructions that cross pages or that diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index d71704cbd2..450dcd8ba0 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -120,12 +120,17 @@ static int hvm_translate_linear_addr( */ addr = (uint32_t)(addr + dreg.base); } - else if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) ) + else { /* - * LONG MODE: FS and GS add a segment base. + * LONG MODE: FS and GS add segment base. Addresses must be canonical. */ - addr += dreg.base; + + if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) ) + addr += dreg.base; + + if ( !is_canonical_address(addr) ) + goto gpf; } *paddr = addr; diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index aafeecf3df..1d2cc8bfdc 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -157,11 +157,15 @@ hvm_paging_enabled(struct vcpu *v) return hvm_funcs.paging_enabled(v); } +#ifdef __x86_64__ static inline int hvm_long_mode_enabled(struct vcpu *v) { return hvm_funcs.long_mode_enabled(v); } +#else +#define hvm_long_mode_enabled(v) 0 +#endif static inline int hvm_pae_enabled(struct vcpu *v) diff --git a/xen/include/asm-x86/x86_32/page.h b/xen/include/asm-x86/x86_32/page.h index 228445a62d..74e36a1a40 100644 --- a/xen/include/asm-x86/x86_32/page.h +++ b/xen/include/asm-x86/x86_32/page.h @@ -7,6 +7,8 @@ #define VADDR_BITS 32 #define VADDR_MASK (~0UL) +#define is_canonical_address(x) 1 + #include #ifdef CONFIG_X86_PAE # include diff --git a/xen/include/asm-x86/x86_64/page.h b/xen/include/asm-x86/x86_64/page.h index 4e0f3675ce..e52097d73e 100644 --- a/xen/include/asm-x86/x86_64/page.h +++ b/xen/include/asm-x86/x86_64/page.h @@ -24,6 +24,8 @@ #define PADDR_MASK ((1UL << PADDR_BITS)-1) #define VADDR_MASK ((1UL << VADDR_BITS)-1) +#define is_canonical_address(x) (((long)(x) >> 47) == ((long)(x) >> 63)) + #ifndef __ASSEMBLY__ #include From bd8806fb71aebdab6289dd42cab8e84301d060ff Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 11:07:22 +0000 Subject: [PATCH 123/282] [XEND] More fixes for HVM device configuration parsing Removed duplicated acpi option, added missing stdvga option. Do not output empty configurations in image sxp. Remove bug with vcpus passing in device model. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 8 ++++---- tools/python/xen/xend/image.py | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 3bb0ba4cd9..846aebda02 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -185,7 +185,6 @@ LEGACY_IMAGE_HVM_CFG = [ ('vncconsole', int), ('pae', int), ('apic', int), - ('acpi', int), ] LEGACY_IMAGE_HVM_DEVICES_CFG = [ @@ -196,7 +195,8 @@ LEGACY_IMAGE_HVM_DEVICES_CFG = [ ('isa', str), ('keymap', str), ('localtime', str), - ('serial', str), + ('serial', str), + ('stdvga', int), ('soundhw', str), ('usb', str), ('usbdevice', str), @@ -987,12 +987,12 @@ class XendConfig(dict): if 'hvm' in self['image']: for arg, conv in LEGACY_IMAGE_HVM_CFG: - if self['image']['hvm'].has_key(arg): + if self['image']['hvm'].get(arg): image.append([arg, self['image']['hvm'][arg]]) if 'hvm' in self['image'] and 'devices' in self['image']['hvm']: for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG: - if self['image']['hvm']['devices'].has_key(arg): + if self['image']['hvm']['devices'].get(arg): image.append([arg, self['image']['hvm']['devices'][arg]]) diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 31194c7a73..8d2aab1836 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -270,8 +270,9 @@ class HVMImageHandler(ImageHandler): self.dmargs += self.configVNC(imageConfig) self.pae = imageConfig['hvm'].get('pae', 0) - self.acpi = imageConfig['hvm'].get('acpi', 0) self.apic = imageConfig['hvm'].get('apic', 0) + self.acpi = imageConfig['hvm']['devices'].get('acpi', 0) + def buildDomain(self): store_evtchn = self.vm.getStorePort() @@ -310,8 +311,6 @@ class HVMImageHandler(ImageHandler): for a in dmargs: v = hvmDeviceConfig.get(a) - if a == 'vcpus': - v = hvmDeviceConfig.get('vcpus_number') # python doesn't allow '-' in variable names if a == 'stdvga': a = 'std-vga' From eb1eb71059074995a758aac068aec0aa0905016d Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 11:32:32 +0000 Subject: [PATCH 124/282] Tidy up the creation of directories that Xend needs. This avoids potential races in this creation. Signed-off-by: Ewan Mellor --- tools/python/xen/util/mkdir.py | 44 +++++++++++++++++++ tools/python/xen/util/xmlrpclib2.py | 13 +++--- tools/python/xen/web/unix.py | 12 +++-- tools/python/xen/xend/XendDomain.py | 37 ++++++---------- tools/python/xen/xend/XendLogging.py | 5 ++- .../python/xen/xend/XendStorageRepository.py | 9 ++-- tools/python/xen/xend/server/SrvDaemon.py | 4 +- 7 files changed, 77 insertions(+), 47 deletions(-) create mode 100644 tools/python/xen/util/mkdir.py diff --git a/tools/python/xen/util/mkdir.py b/tools/python/xen/util/mkdir.py new file mode 100644 index 0000000000..121e498a23 --- /dev/null +++ b/tools/python/xen/util/mkdir.py @@ -0,0 +1,44 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (c) 2006 XenSource Inc. +#============================================================================ + +import errno +import os +import os.path +import stat + + +def parents(dir, perms, enforcePermissions = False): + """ + Ensure that the given directory exists, creating it if necessary, but not + complaining if it's already there. + + @param dir The directory name. + @param perms One of the stat.S_ constants. + @param enforcePermissions Enforce our ownership and the given permissions, + even if the directory pre-existed with different ones. + """ + # Catch the exception here, rather than checking for the directory's + # existence first, to avoid races. + try: + os.makedirs(dir, perms) + except OSError, exn: + if exn.args[0] != errno.EEXIST or not os.path.isdir(dir): + raise + if enforcePermissions: + os.chown(dir, os.geteuid(), os.getegid()) + os.chmod(dir, stat.S_IRWXU) diff --git a/tools/python/xen/util/xmlrpclib2.py b/tools/python/xen/util/xmlrpclib2.py index 3a3973f838..efb29d7b0e 100644 --- a/tools/python/xen/util/xmlrpclib2.py +++ b/tools/python/xen/util/xmlrpclib2.py @@ -30,6 +30,8 @@ from SimpleXMLRPCServer import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler import SocketServer import xmlrpclib, socket, os, stat +import mkdir + from xen.web import connection from xen.xend.XendLogging import log @@ -234,14 +236,9 @@ class UnixXMLRPCServer(TCPXMLRPCServer): address_family = socket.AF_UNIX def __init__(self, addr, allowed, logRequests = 1): - parent = os.path.dirname(addr) - if os.path.exists(parent): - os.chown(parent, os.geteuid(), os.getegid()) - os.chmod(parent, stat.S_IRWXU) - if self.allow_reuse_address and os.path.exists(addr): - os.unlink(addr) - else: - os.makedirs(parent, stat.S_IRWXU) + mkdir.parents(os.path.dirname(addr), stat.S_IRWXU, True) + if self.allow_reuse_address and os.path.exists(addr): + os.unlink(addr) TCPXMLRPCServer.__init__(self, addr, allowed, UnixXMLRPCRequestHandler, logRequests) diff --git a/tools/python/xen/web/unix.py b/tools/python/xen/web/unix.py index 8ec715c12f..12b6e9694e 100644 --- a/tools/python/xen/web/unix.py +++ b/tools/python/xen/web/unix.py @@ -22,6 +22,8 @@ import os.path import socket import stat +from xen.util import mkdir + import connection @@ -30,13 +32,9 @@ def bind(path): created such that only the current user may access it.""" parent = os.path.dirname(path) - if os.path.exists(parent): - os.chown(parent, os.geteuid(), os.getegid()) - os.chmod(parent, stat.S_IRWXU) - if os.path.exists(path): - os.unlink(path) - else: - os.makedirs(parent, stat.S_IRWXU) + mkdir.parents(parent, stat.S_IRWXU, True) + if os.path.exists(path): + os.unlink(path) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.bind(path) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 9a4d112e95..bb14e70667 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -23,6 +23,7 @@ """ import os +import stat import shutil import socket import threading @@ -44,7 +45,7 @@ from xen.xend.XendDevices import XendDevices from xen.xend.xenstore.xstransact import xstransact from xen.xend.xenstore.xswatch import xswatch -from xen.util import security +from xen.util import mkdir, security from xen.xend import uuid xc = xen.lowlevel.xc.xc() @@ -99,11 +100,7 @@ class XendDomain: """Singleton initialisation function.""" dom_path = self._managed_path() - try: - os.stat(dom_path) - except OSError: - log.info("Making %s", dom_path) - os.makedirs(dom_path, 0755) + mkdir.parents(dom_path, stat.S_IRWXU) xstransact.Mkdir(XS_VMROOT) xstransact.SetPermissions(XS_VMROOT, {'dom': DOM0_ID}) @@ -271,25 +268,17 @@ class XendDomain: domains_dir = self._managed_path() dom_uuid = dominfo.get_uuid() domain_config_dir = self._managed_path(dom_uuid) - - # make sure the domain dir exists - if not os.path.exists(domains_dir): - os.makedirs(domains_dir, 0755) - elif not os.path.isdir(domains_dir): - log.error("xend_domain_dir is not a directory.") - raise XendError("Unable to save managed configuration " - "because %s is not a directory." % - domains_dir) - - if not os.path.exists(domain_config_dir): + + def make_or_raise(path): try: - os.makedirs(domain_config_dir, 0755) - except IOError: - log.exception("Failed to create directory: %s" % - domain_config_dir) - raise XendError("Failed to create directory: %s" % - domain_config_dir) - + mkdir.parents(path, stat.S_IRWXU) + except: + log.exception("%s could not be created." % path) + raise XendError("%s could not be created." % path) + + make_or_raise(domains_dir) + make_or_raise(domain_config_dir) + try: sxp_cache_file = open(self._managed_config_path(dom_uuid),'w') prettyprint(dominfo.sxpr(), sxp_cache_file, width = 78) diff --git a/tools/python/xen/xend/XendLogging.py b/tools/python/xen/xend/XendLogging.py index a3d6de86d1..32cd13c5db 100644 --- a/tools/python/xen/xend/XendLogging.py +++ b/tools/python/xen/xend/XendLogging.py @@ -16,13 +16,15 @@ # Copyright (C) 2005, 2006 XenSource Ltd. #============================================================================ - +import os +import stat import tempfile import types import logging import logging.handlers import fcntl +from xen.util import mkdir from xen.xend.server import params @@ -80,6 +82,7 @@ def init(filename, level): global logfilename def openFileHandler(fname): + mkdir.parents(os.path.dirname(fname), stat.S_IRWXU) return XendRotatingFileHandler(fname, mode = 'a', maxBytes = MAX_BYTES, backupCount = BACKUP_COUNT) diff --git a/tools/python/xen/xend/XendStorageRepository.py b/tools/python/xen/xend/XendStorageRepository.py index d906f5b5fd..a16a293191 100644 --- a/tools/python/xen/xend/XendStorageRepository.py +++ b/tools/python/xen/xend/XendStorageRepository.py @@ -19,10 +19,12 @@ # The default QCOW Xen API Storage Repository # -import os import commands +import os +import stat import threading +from xen.util import mkdir from xen.xend import uuid from xen.xend.XendError import XendError from xen.xend.XendVDI import * @@ -98,10 +100,7 @@ class XendStorageRepository: """ self.lock.acquire() try: - # create directory if /var/lib/xend/storage does not exist - if not os.path.exists(XEND_STORAGE_DIR): - os.makedirs(XEND_STORAGE_DIR) - os.chmod(XEND_STORAGE_DIR, 0700) + mkdir.parents(XEND_STORAGE_DIR, stat.S_IRWXU) # scan the directory and populate self.images total_used = 0 diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 7bfa466dff..35c64869d4 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -21,6 +21,7 @@ import xen.lowlevel.xc from xen.xend.XendLogging import log from xen.xend import osdep +from xen.util import mkdir import relocate import SrvServer @@ -108,8 +109,7 @@ class Daemon: # so _before_ we close stderr. try: parent = os.path.dirname(XEND_DEBUG_LOG) - if not os.path.exists(parent): - os.makedirs(parent, stat.S_IRWXU) + mkdir.parents(parent, stat.S_IRWXU) fd = os.open(XEND_DEBUG_LOG, os.O_WRONLY|os.O_CREAT|os.O_APPEND) except Exception, exn: print >>sys.stderr, exn From 6bebf0edee8d13c745d52bc60253e216571c2772 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 11:49:30 +0000 Subject: [PATCH 125/282] [PVFB][TOOLS] Change the configuration syntax for PVFB backends to more closely match that of other devices. This involves moving the logic for backend creation out of the image handlers and in to the device handler, which is a much more sensible place for it. Signed-off-by: Steven Smith --- tools/python/xen/xend/XendDomainInfo.py | 19 +------ tools/python/xen/xend/image.py | 67 ------------------------- tools/python/xen/xend/server/vfbif.py | 34 +++++++++++-- tools/python/xen/xm/create.py | 54 +++++++++++--------- 4 files changed, 61 insertions(+), 113 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 152022477e..d606dbb7bb 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -458,7 +458,7 @@ class XendDomainInfo: try: self._constructDomain() self._storeVmDetails() - self._restoreDomain() + self._createDevices() self._createChannels() self._storeDomDetails() self._endRestore() @@ -1387,23 +1387,6 @@ class XendDomainInfo: raise VmError(str(exn)) - def _restoreDomain(self): - log.debug('XendDomainInfo.restoreDomain: %s %s', - self.domid, - self.info['cpu_weight']) - - if not self.infoIsSet('image'): - raise VmError('Missing image in configuration') - - try: - self.image = image.create(self, - self.info['image'], - self.info['device']) - - self._createDevices() - except RuntimeError, exn: - raise VmError(str(exn)) - def cleanupDomain(self): """Cleanup domain resources; release devices. Idempotent. Nothrow guarantee.""" diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 10acfd6674..1023197927 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -23,7 +23,6 @@ import math import signal import xen.lowlevel.xc -import xen.util.auxbin from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS from xen.xend.XendError import VmError, XendError from xen.xend.XendLogging import log @@ -200,72 +199,6 @@ class LinuxImageHandler(ImageHandler): ramdisk = self.ramdisk, features = self.vm.getFeatures()) - def configure(self, imageConfig, deviceConfig): - ImageHandler.configure(self, imageConfig, deviceConfig) - - self.pid = 0 - log.info("configuring linux guest") - - # set up the graphics bits. - # FIXME: this is much like what we do for HVM, should it be - # for all image types now? - self.display = sxp.child_value(imageConfig, 'display') - self.xauthority = sxp.child_value(imageConfig, 'xauthority') - self.vncconsole = sxp.child_value(imageConfig, 'vncconsole') - vncpasswd = sxp.child_value(imageConfig, 'vncpasswd') - self.vncpasswd = vncpasswd - - self.vnc = sxp.child_value(imageConfig, 'vnc') - self.sdl = sxp.child_value(imageConfig, 'sdl') - if self.vnc: - self.vncdisplay = int(sxp.child_value(imageConfig, 'vncdisplay', - self.vm.getDomid())) - self.vncunused = sxp.child_value(imageConfig, 'vncunused') - self.vnclisten = sxp.child_value(imageConfig, 'vnclisten') - if not(self.vnclisten): - self.vnclisten = xen.xend.XendRoot.instance().get_vnclisten_address() - - def createDeviceModel(self): - if self.pid: - return - # Execute device model (for us, it's just the fb frontend) - if not self.vnc and not self.sdl: - return - - if self.vnc: - args = [xen.util.auxbin.pathTo("xen-vncfb")] - if self.vncunused: - args += ['--unused'] - elif self.vncdisplay: - args += [ "--vncport", "%d" %(5900 + self.vncdisplay,) ] - if self.vnclisten: - args += [ "--listen", self.vnclisten ] - - # password check - if self.vncpasswd is None: - # get password from xend-config(if password omitted, None) - self.vncpasswd = xen.xend.XendRoot.instance().get_vncpasswd_default() - - if self.vncpasswd is None: - raise VmError('vncpasswd is not setup in the guest config or xend-config.') - if self.vncpasswd != '': - self.vm.storeVm("vncpasswd", self.vncpasswd) - log.info("vncpassword set to '%s'", self.vncpasswd) - - elif self.sdl: - args = [xen.util.auxbin.pathTo("xen-sdlfb")] - args = args + [ "--domid", "%d" % self.vm.getDomid(), - "--title", self.vm.info['name'] ] - - env = dict(os.environ) - if self.display: - env['DISPLAY'] = self.display - if self.xauthority: - env['XAUTHORITY'] = self.xauthority - log.info("spawning video: %s", args) - self.pid = os.spawnve(os.P_NOWAIT, args[0], args, env) - log.info("device model pid: %d", self.pid) - def destroy(self): if not self.pid: return diff --git a/tools/python/xen/xend/server/vfbif.py b/tools/python/xen/xend/server/vfbif.py index 7f9691698f..4540031633 100644 --- a/tools/python/xen/xend/server/vfbif.py +++ b/tools/python/xen/xend/server/vfbif.py @@ -1,5 +1,9 @@ from xen.xend.server.DevController import DevController +from xen.xend.XendError import VmError +import xen.xend +import os + class VfbifController(DevController): """Virtual frame buffer controller. Handles all vfb devices for a domain. """ @@ -14,13 +18,37 @@ class VfbifController(DevController): front = {} return (devid, back, front) + def createDevice(self, config): + DevController.createDevice(self, config) + std_args = [ "--domid", "%d" % self.vm.getDomid(), + "--title", self.vm.getName() ] + t = config.get("type", None) + if t == "vnc": + # Try to start the vnc backend + args = [xen.util.auxbin.pathTo("xen-vncfb")] + if config.has_key("vncunused"): + args += ["--unused"] + elif config.has_key("vncdisplay"): + args += ["--vncport", "%d" % (5900 + config["vncdisplay"])] + vnclisten = config.get("vnclisten", + xen.xend.XendRoot.instance().get_vnclisten_address()) + args += [ "--listen", vnclisten ] + os.spawnve(os.P_NOWAIT, args[0], args + std_args, os.environ) + elif t == "sdl": + args = [xen.util.auxbin.pathTo("xen-sdlfb")] + env = dict(os.environ) + if config.has_key("display"): + env['DISPLAY'] = config["display"] + if config.has_key("xauthority"): + env['XAUTHORITY'] = config["xauthority"] + os.spawnve(os.P_NOWAIT, args[0], args + std_args, env) + else: + raise VmError('Unknown vfb type %s (%s)' % (t, repr(config))) + class VkbdifController(DevController): """Virtual keyboard controller. Handles all vkbd devices for a domain. """ - def __init__(self, vm): - DevController.__init__(self, vm) - def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" devid = 0 diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index c4bca1130a..8b5301b9e8 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -284,13 +284,17 @@ gopts.var('usbport', val='PATH', use="""Add a physical USB port to a domain, as specified by the path to that port. This option may be repeated to add more than one port.""") -gopts.var('vfb', val="no|yes'", - fn=set_bool, default=0, - use="Make the domain a framebuffer backend.") - -gopts.var('vkbd', val="no|yes'", - fn=set_bool, default=0, - use="Make the domain a keyboard backend.") +gopts.var('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY", + fn=append_value, default=[], + use="""Make the domain a framebuffer backend. + The backend type should be either sdl or vnc. + For type=vnc, connect an external vncviewer. The server will listen + on ADDR (default 127.0.0.1) on port N+5900. N defaults to the + domain id. If vncunused=1, the server will try to find an arbitrary + unused port above 5900. + For type=sdl, a viewer will be started automatically using the + given DISPLAY and XAUTHORITY, which default to the current user's + ones.""") gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME", fn=append_value, default=[], @@ -521,8 +525,6 @@ def configure_image(vals): if vals.builder == 'hvm': configure_hvm(config_image, vals) - - configure_graphics(config_image, vals) return config_image @@ -575,12 +577,22 @@ def configure_usb(config_devs, vals): config_devs.append(['device', config_usb]) def configure_vfbs(config_devs, vals): - if vals.vfb: - config_devs.append(['device', ['vfb', []]]) - -def configure_vkbds(config_devs, vals): - if vals.vkbd: - config_devs.append(['device', ['vkbd', []]]) + for f in vals.vfb: + d = comma_sep_kv_to_dict(f) + config = ['vfb'] + if not d.has_key("type"): + d['type'] = 'sdl' + for (k,v) in d.iteritems(): + if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display', + 'xauthority', 'type' ]: + err("configuration option %s unknown to vfbs" % k) + config.append([k,v]) + if not d.has_key("display") and os.environ.has_key("DISPLAY"): + config.append(["display", os.environ['DISPLAY']]) + if not d.has_key("xauthority"): + config.append(["xauthority", get_xauthority()]) + config_devs.append(['device', ['vkbd']]) + config_devs.append(['device', config]) def configure_security(config, vals): """Create the config for ACM security labels. @@ -678,20 +690,13 @@ def configure_vifs(config_devs, vals): config_devs.append(['device', config_vif]) -def configure_graphics(config_image, vals): - """Create the config for graphic consoles. - """ - args = [ 'vnc', 'vncdisplay', 'vncconsole', 'vncunused', - 'sdl', 'display', 'xauthority', 'vnclisten', 'vncpasswd'] - for a in args: - if (vals.__dict__[a]): - config_image.append([a, vals.__dict__[a]]) - def configure_hvm(config_image, vals): """Create the config for HVM devices. """ args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb', 'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw', + 'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten', + 'sdl', 'display', 'xauthority', 'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ] for a in args: if a in vals.__dict__ and vals.__dict__[a] is not None: @@ -767,7 +772,6 @@ def make_config(vals): configure_usb(config_devs, vals) configure_vtpm(config_devs, vals) configure_vfbs(config_devs, vals) - configure_vkbds(config_devs, vals) configure_security(config, vals) config += config_devs From 3c78f2e5d746fb3f484f6249f3f982b670205d39 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 11:52:33 +0000 Subject: [PATCH 126/282] [LINUX] The removal of the console_use_vt hack was premature: it's still required if CONFIG_VT is enabled but the domain isn't currently configured to use the PV framebuffer. Put it back in, in a slightly more palatable form. Signed-off-by: Steven Smith --- .../arch/i386/kernel/setup-xen.c | 1 + linux-2.6-xen-sparse/arch/ia64/kernel/setup.c | 2 + .../arch/x86_64/kernel/setup-xen.c | 3 +- linux-2.6-xen-sparse/drivers/char/tty_io.c | 3264 +++++++++++++++++ .../drivers/xen/console/console.c | 34 +- linux-2.6-xen-sparse/include/xen/xencons.h | 2 + 6 files changed, 3289 insertions(+), 17 deletions(-) create mode 100644 linux-2.6-xen-sparse/drivers/char/tty_io.c diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c index e8a96c7c6d..819f36f11e 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c @@ -1871,6 +1871,7 @@ void __init setup_arch(char **cmdline_p) conswitchp = &dummy_con; #endif } + xencons_early_setup(); } static int diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c index 76d4b8824b..4158332846 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c @@ -555,9 +555,11 @@ setup_arch (char **cmdline_p) #endif } } + xencons_early_setup(); #endif #endif + /* enable IA-64 Machine Check Abort Handling unless disabled */ if (!strstr(saved_command_line, "nomca")) ia64_mca_init(); diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c index 3bc217a8c6..43e53c88e4 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c @@ -984,10 +984,11 @@ void __init setup_arch(char **cmdline_p) #endif } else { #if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE) - conswitchp = &dummy_con; + conswitchp = &dummy_con; #endif } } + xencons_early_setup(); #else /* CONFIG_XEN */ #ifdef CONFIG_VT diff --git a/linux-2.6-xen-sparse/drivers/char/tty_io.c b/linux-2.6-xen-sparse/drivers/char/tty_io.c new file mode 100644 index 0000000000..0372d93bca --- /dev/null +++ b/linux-2.6-xen-sparse/drivers/char/tty_io.c @@ -0,0 +1,3264 @@ +/* + * linux/drivers/char/tty_io.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc. + * + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. + * + * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the + * tty_struct and tty_queue structures. Previously there was an array + * of 256 tty_struct's which was statically allocated, and the + * tty_queue structures were allocated at boot time. Both are now + * dynamically allocated only when the tty is open. + * + * Also restructured routines so that there is more of a separation + * between the high-level tty routines (tty_io.c and tty_ioctl.c) and + * the low-level tty routines (serial.c, pty.c, console.c). This + * makes for cleaner and more compact code. -TYT, 9/17/92 + * + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines + * which can be dynamically activated and de-activated by the line + * discipline handling modules (like SLIP). + * + * NOTE: pay no attention to the line discipline code (yet); its + * interface is still subject to change in this version... + * -- TYT, 1/31/92 + * + * Added functionality to the OPOST tty handling. No delays, but all + * other bits should be there. + * -- Nick Holloway , 27th May 1993. + * + * Rewrote canonical mode and added more termios flags. + * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 + * + * Reorganized FASYNC support so mouse code can share it. + * -- ctm@ardi.com, 9Sep95 + * + * New TIOCLINUX variants added. + * -- mj@k332.feld.cvut.cz, 19-Nov-95 + * + * Restrict vt switching via ioctl() + * -- grif@cs.ucr.edu, 5-Dec-95 + * + * Move console and virtual terminal code to more appropriate files, + * implement CONFIG_VT and generalize console device interface. + * -- Marko Kohtala , March 97 + * + * Rewrote init_dev and release_dev to eliminate races. + * -- Bill Hawes , June 97 + * + * Added devfs support. + * -- C. Scott Ananian , 13-Jan-1998 + * + * Added support for a Unix98-style ptmx device. + * -- C. Scott Ananian , 14-Jan-1998 + * + * Reduced memory usage for older ARM systems + * -- Russell King + * + * Move do_SAK() into process context. Less stack use in devfs functions. + * alloc_tty_struct() always uses kmalloc() -- Andrew Morton 17Mar01 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#undef TTY_DEBUG_HANGUP + +#define TTY_PARANOIA_CHECK 1 +#define CHECK_TTY_COUNT 1 + +struct termios tty_std_termios = { /* for the benefit of tty drivers */ + .c_iflag = ICRNL | IXON, + .c_oflag = OPOST | ONLCR, + .c_cflag = B38400 | CS8 | CREAD | HUPCL, + .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | + ECHOCTL | ECHOKE | IEXTEN, + .c_cc = INIT_C_CC +}; + +EXPORT_SYMBOL(tty_std_termios); + +/* This list gets poked at by procfs and various bits of boot up code. This + could do with some rationalisation such as pulling the tty proc function + into this file */ + +LIST_HEAD(tty_drivers); /* linked list of tty drivers */ + +/* Semaphore to protect creating and releasing a tty. This is shared with + vt.c for deeply disgusting hack reasons */ +DECLARE_MUTEX(tty_sem); + +int console_use_vt = 1; + +#ifdef CONFIG_UNIX98_PTYS +extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ +extern int pty_limit; /* Config limit on Unix98 ptys */ +static DEFINE_IDR(allocated_ptys); +static DECLARE_MUTEX(allocated_ptys_lock); +static int ptmx_open(struct inode *, struct file *); +#endif + +extern void disable_early_printk(void); + +static void initialize_tty_struct(struct tty_struct *tty); + +static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); +ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *); +static unsigned int tty_poll(struct file *, poll_table *); +static int tty_open(struct inode *, struct file *); +static int tty_release(struct inode *, struct file *); +int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); +static int tty_fasync(int fd, struct file * filp, int on); +static void release_mem(struct tty_struct *tty, int idx); + + +static struct tty_struct *alloc_tty_struct(void) +{ + struct tty_struct *tty; + + tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL); + if (tty) + memset(tty, 0, sizeof(struct tty_struct)); + return tty; +} + +static void tty_buffer_free_all(struct tty_struct *); + +static inline void free_tty_struct(struct tty_struct *tty) +{ + kfree(tty->write_buf); + tty_buffer_free_all(tty); + kfree(tty); +} + +#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) + +char *tty_name(struct tty_struct *tty, char *buf) +{ + if (!tty) /* Hmm. NULL pointer. That's fun. */ + strcpy(buf, "NULL tty"); + else + strcpy(buf, tty->name); + return buf; +} + +EXPORT_SYMBOL(tty_name); + +int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, + const char *routine) +{ +#ifdef TTY_PARANOIA_CHECK + if (!tty) { + printk(KERN_WARNING + "null TTY for (%d:%d) in %s\n", + imajor(inode), iminor(inode), routine); + return 1; + } + if (tty->magic != TTY_MAGIC) { + printk(KERN_WARNING + "bad magic number for tty struct (%d:%d) in %s\n", + imajor(inode), iminor(inode), routine); + return 1; + } +#endif + return 0; +} + +static int check_tty_count(struct tty_struct *tty, const char *routine) +{ +#ifdef CHECK_TTY_COUNT + struct list_head *p; + int count = 0; + + file_list_lock(); + list_for_each(p, &tty->tty_files) { + count++; + } + file_list_unlock(); + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_SLAVE && + tty->link && tty->link->count) + count++; + if (tty->count != count) { + printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) " + "!= #fd's(%d) in %s\n", + tty->name, tty->count, count, routine); + return count; + } +#endif + return 0; +} + +/* + * Tty buffer allocation management + */ + +static void tty_buffer_free_all(struct tty_struct *tty) +{ + struct tty_buffer *thead; + while((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + kfree(thead); + } + while((thead = tty->buf.free) != NULL) { + tty->buf.free = thead->next; + kfree(thead); + } + tty->buf.tail = NULL; +} + +static void tty_buffer_init(struct tty_struct *tty) +{ + spin_lock_init(&tty->buf.lock); + tty->buf.head = NULL; + tty->buf.tail = NULL; + tty->buf.free = NULL; +} + +static struct tty_buffer *tty_buffer_alloc(size_t size) +{ + struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); + if(p == NULL) + return NULL; + p->used = 0; + p->size = size; + p->next = NULL; + p->active = 0; + p->commit = 0; + p->read = 0; + p->char_buf_ptr = (char *)(p->data); + p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; +/* printk("Flip create %p\n", p); */ + return p; +} + +/* Must be called with the tty_read lock held. This needs to acquire strategy + code to decide if we should kfree or relink a given expired buffer */ + +static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) +{ + /* Dumb strategy for now - should keep some stats */ +/* printk("Flip dispose %p\n", b); */ + if(b->size >= 512) + kfree(b); + else { + b->next = tty->buf.free; + tty->buf.free = b; + } +} + +static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) +{ + struct tty_buffer **tbh = &tty->buf.free; + while((*tbh) != NULL) { + struct tty_buffer *t = *tbh; + if(t->size >= size) { + *tbh = t->next; + t->next = NULL; + t->used = 0; + t->commit = 0; + t->read = 0; + /* DEBUG ONLY */ +/* memset(t->data, '*', size); */ +/* printk("Flip recycle %p\n", t); */ + return t; + } + tbh = &((*tbh)->next); + } + /* Round the buffer size out */ + size = (size + 0xFF) & ~ 0xFF; + return tty_buffer_alloc(size); + /* Should possibly check if this fails for the largest buffer we + have queued and recycle that ? */ +} + +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + struct tty_buffer *b, *n; + int left; + unsigned long flags; + + spin_lock_irqsave(&tty->buf.lock, flags); + + /* OPTIMISATION: We could keep a per tty "zero" sized buffer to + remove this conditional if its worth it. This would be invisible + to the callers */ + if ((b = tty->buf.tail) != NULL) { + left = b->size - b->used; + b->active = 1; + } else + left = 0; + + if (left < size) { + /* This is the slow path - looking for new buffers to use */ + if ((n = tty_buffer_find(tty, size)) != NULL) { + if (b != NULL) { + b->next = n; + b->active = 0; + b->commit = b->used; + } else + tty->buf.head = n; + tty->buf.tail = n; + n->active = 1; + } else + size = left; + } + + spin_unlock_irqrestore(&tty->buf.lock, flags); + return size; +} + +EXPORT_SYMBOL_GPL(tty_buffer_request_room); + +int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if(unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + copied += space; + chars += space; +/* printk("Flip insert %d.\n", space); */ + } + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + while (unlikely(size > copied)); + return copied; +} + +EXPORT_SYMBOL_GPL(tty_insert_flip_string); + +int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if(unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memcpy(tb->flag_buf_ptr + tb->used, flags, space); + tb->used += space; + copied += space; + chars += space; + flags += space; + } + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + while (unlikely(size > copied)); + return copied; +} + +EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); + + +/* + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for normal characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + */ + +int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) +{ + int space = tty_buffer_request_room(tty, size); + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + } + return space; +} + +EXPORT_SYMBOL_GPL(tty_prepare_flip_string); + +/* + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + */ + +int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) +{ + int space = tty_buffer_request_room(tty, size); + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + *flags = tb->flag_buf_ptr + tb->used; + tb->used += space; + } + return space; +} + +EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); + + + +/* + * This is probably overkill for real world processors but + * they are not on hot paths so a little discipline won't do + * any harm. + */ + +static void tty_set_termios_ldisc(struct tty_struct *tty, int num) +{ + down(&tty->termios_sem); + tty->termios->c_line = num; + up(&tty->termios_sem); +} + +/* + * This guards the refcounted line discipline lists. The lock + * must be taken with irqs off because there are hangup path + * callers who will do ldisc lookups and cannot sleep. + */ + +static DEFINE_SPINLOCK(tty_ldisc_lock); +static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); +static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ + +int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) +{ + unsigned long flags; + int ret = 0; + + if (disc < N_TTY || disc >= NR_LDISCS) + return -EINVAL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + tty_ldiscs[disc] = *new_ldisc; + tty_ldiscs[disc].num = disc; + tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + tty_ldiscs[disc].refcount = 0; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + + return ret; +} +EXPORT_SYMBOL(tty_register_ldisc); + +int tty_unregister_ldisc(int disc) +{ + unsigned long flags; + int ret = 0; + + if (disc < N_TTY || disc >= NR_LDISCS) + return -EINVAL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if (tty_ldiscs[disc].refcount) + ret = -EBUSY; + else + tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + + return ret; +} +EXPORT_SYMBOL(tty_unregister_ldisc); + +struct tty_ldisc *tty_ldisc_get(int disc) +{ + unsigned long flags; + struct tty_ldisc *ld; + + if (disc < N_TTY || disc >= NR_LDISCS) + return NULL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + + ld = &tty_ldiscs[disc]; + /* Check the entry is defined */ + if(ld->flags & LDISC_FLAG_DEFINED) + { + /* If the module is being unloaded we can't use it */ + if (!try_module_get(ld->owner)) + ld = NULL; + else /* lock it */ + ld->refcount++; + } + else + ld = NULL; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return ld; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_get); + +void tty_ldisc_put(int disc) +{ + struct tty_ldisc *ld; + unsigned long flags; + + if (disc < N_TTY || disc >= NR_LDISCS) + BUG(); + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld = &tty_ldiscs[disc]; + if(ld->refcount == 0) + BUG(); + ld->refcount --; + module_put(ld->owner); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} + +EXPORT_SYMBOL_GPL(tty_ldisc_put); + +static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld) +{ + tty->ldisc = *ld; + tty->ldisc.refcount = 0; +} + +/** + * tty_ldisc_try - internal helper + * @tty: the tty + * + * Make a single attempt to grab and bump the refcount on + * the tty ldisc. Return 0 on failure or 1 on success. This is + * used to implement both the waiting and non waiting versions + * of tty_ldisc_ref + */ + +static int tty_ldisc_try(struct tty_struct *tty) +{ + unsigned long flags; + struct tty_ldisc *ld; + int ret = 0; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + ld = &tty->ldisc; + if(test_bit(TTY_LDISC, &tty->flags)) + { + ld->refcount++; + ret = 1; + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + return ret; +} + +/** + * tty_ldisc_ref_wait - wait for the tty ldisc + * @tty: tty device + * + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then + * wait patiently until it changes. + * + * Note: Must not be called from an IRQ/timer context. The caller + * must also be careful not to hold other locks that will deadlock + * against a discipline change, such as an existing ldisc reference + * (which we check for) + */ + +struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) +{ + /* wait_event is a macro */ + wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); + if(tty->ldisc.refcount == 0) + printk(KERN_ERR "tty_ldisc_ref_wait\n"); + return &tty->ldisc; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); + +/** + * tty_ldisc_ref - get the tty ldisc + * @tty: tty device + * + * Dereference the line discipline for the terminal and take a + * reference to it. If the line discipline is in flux then + * return NULL. Can be called from IRQ and timer functions. + */ + +struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) +{ + if(tty_ldisc_try(tty)) + return &tty->ldisc; + return NULL; +} + +EXPORT_SYMBOL_GPL(tty_ldisc_ref); + +/** + * tty_ldisc_deref - free a tty ldisc reference + * @ld: reference to free up + * + * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May + * be called in IRQ context. + */ + +void tty_ldisc_deref(struct tty_ldisc *ld) +{ + unsigned long flags; + + if(ld == NULL) + BUG(); + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if(ld->refcount == 0) + printk(KERN_ERR "tty_ldisc_deref: no references.\n"); + else + ld->refcount--; + if(ld->refcount == 0) + wake_up(&tty_ldisc_wait); + spin_unlock_irqrestore(&tty_ldisc_lock, flags); +} + +EXPORT_SYMBOL_GPL(tty_ldisc_deref); + +/** + * tty_ldisc_enable - allow ldisc use + * @tty: terminal to activate ldisc on + * + * Set the TTY_LDISC flag when the line discipline can be called + * again. Do neccessary wakeups for existing sleepers. + * + * Note: nobody should set this bit except via this function. Clearing + * directly is allowed. + */ + +static void tty_ldisc_enable(struct tty_struct *tty) +{ + set_bit(TTY_LDISC, &tty->flags); + wake_up(&tty_ldisc_wait); +} + +/** + * tty_set_ldisc - set line discipline + * @tty: the terminal to set + * @ldisc: the line discipline + * + * Set the discipline of a tty line. Must be called from a process + * context. + */ + +static int tty_set_ldisc(struct tty_struct *tty, int ldisc) +{ + int retval = 0; + struct tty_ldisc o_ldisc; + char buf[64]; + int work; + unsigned long flags; + struct tty_ldisc *ld; + struct tty_struct *o_tty; + + if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS)) + return -EINVAL; + +restart: + + ld = tty_ldisc_get(ldisc); + /* Eduardo Blanco */ + /* Cyrus Durgin */ + if (ld == NULL) { + request_module("tty-ldisc-%d", ldisc); + ld = tty_ldisc_get(ldisc); + } + if (ld == NULL) + return -EINVAL; + + /* + * No more input please, we are switching. The new ldisc + * will update this value in the ldisc open function + */ + + tty->receive_room = 0; + + /* + * Problem: What do we do if this blocks ? + */ + + tty_wait_until_sent(tty, 0); + + if (tty->ldisc.num == ldisc) { + tty_ldisc_put(ldisc); + return 0; + } + + o_ldisc = tty->ldisc; + o_tty = tty->link; + + /* + * Make sure we don't change while someone holds a + * reference to the line discipline. The TTY_LDISC bit + * prevents anyone taking a reference once it is clear. + * We need the lock to avoid racing reference takers. + */ + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { + if(tty->ldisc.refcount) { + /* Free the new ldisc we grabbed. Must drop the lock + first. */ + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + /* + * There are several reasons we may be busy, including + * random momentary I/O traffic. We must therefore + * retry. We could distinguish between blocking ops + * and retries if we made tty_ldisc_wait() smarter. That + * is up for discussion. + */ + if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + if(o_tty && o_tty->ldisc.refcount) { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) + return -ERESTARTSYS; + goto restart; + } + } + + /* if the TTY_LDISC bit is set, then we are racing against another ldisc change */ + + if (!test_bit(TTY_LDISC, &tty->flags)) { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + tty_ldisc_put(ldisc); + ld = tty_ldisc_ref_wait(tty); + tty_ldisc_deref(ld); + goto restart; + } + + clear_bit(TTY_LDISC, &tty->flags); + clear_bit(TTY_DONT_FLIP, &tty->flags); + if (o_tty) { + clear_bit(TTY_LDISC, &o_tty->flags); + clear_bit(TTY_DONT_FLIP, &o_tty->flags); + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + + /* + * From this point on we know nobody has an ldisc + * usage reference, nor can they obtain one until + * we say so later on. + */ + + work = cancel_delayed_work(&tty->buf.work); + /* + * Wait for ->hangup_work and ->buf.work handlers to terminate + */ + + flush_scheduled_work(); + /* Shutdown the current discipline. */ + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + + /* Now set up the new line discipline. */ + tty_ldisc_assign(tty, ld); + tty_set_termios_ldisc(tty, ldisc); + if (tty->ldisc.open) + retval = (tty->ldisc.open)(tty); + if (retval < 0) { + tty_ldisc_put(ldisc); + /* There is an outstanding reference here so this is safe */ + tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num)); + tty_set_termios_ldisc(tty, tty->ldisc.num); + if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) { + tty_ldisc_put(o_ldisc.num); + /* This driver is always present */ + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(tty, N_TTY); + if (tty->ldisc.open) { + int r = tty->ldisc.open(tty); + + if (r < 0) + panic("Couldn't open N_TTY ldisc for " + "%s --- error %d.", + tty_name(tty, buf), r); + } + } + } + /* At this point we hold a reference to the new ldisc and a + a reference to the old ldisc. If we ended up flipping back + to the existing ldisc we have two references to it */ + + if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) + tty->driver->set_ldisc(tty); + + tty_ldisc_put(o_ldisc.num); + + /* + * Allow ldisc referencing to occur as soon as the driver + * ldisc callback completes. + */ + + tty_ldisc_enable(tty); + if (o_tty) + tty_ldisc_enable(o_tty); + + /* Restart it in case no characters kick it off. Safe if + already running */ + if (work) + schedule_delayed_work(&tty->buf.work, 1); + return retval; +} + +/* + * This routine returns a tty driver structure, given a device number + */ +static struct tty_driver *get_tty_driver(dev_t device, int *index) +{ + struct tty_driver *p; + + list_for_each_entry(p, &tty_drivers, tty_drivers) { + dev_t base = MKDEV(p->major, p->minor_start); + if (device < base || device >= base + p->num) + continue; + *index = device - base; + return p; + } + return NULL; +} + +/* + * If we try to write to, or set the state of, a terminal and we're + * not in the foreground, send a SIGTTOU. If the signal is blocked or + * ignored, go ahead and perform the operation. (POSIX 7.2) + */ +int tty_check_change(struct tty_struct * tty) +{ + if (current->signal->tty != tty) + return 0; + if (tty->pgrp <= 0) { + printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n"); + return 0; + } + if (process_group(current) == tty->pgrp) + return 0; + if (is_ignored(SIGTTOU)) + return 0; + if (is_orphaned_pgrp(process_group(current))) + return -EIO; + (void) kill_pg(process_group(current), SIGTTOU, 1); + return -ERESTARTSYS; +} + +EXPORT_SYMBOL(tty_check_change); + +static ssize_t hung_up_tty_read(struct file * file, char __user * buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t hung_up_tty_write(struct file * file, const char __user * buf, + size_t count, loff_t *ppos) +{ + return -EIO; +} + +/* No kernel lock held - none needed ;) */ +static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait) +{ + return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; +} + +static int hung_up_tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + return cmd == TIOCSPGRP ? -ENOTTY : -EIO; +} + +static struct file_operations tty_fops = { + .llseek = no_llseek, + .read = tty_read, + .write = tty_write, + .poll = tty_poll, + .ioctl = tty_ioctl, + .open = tty_open, + .release = tty_release, + .fasync = tty_fasync, +}; + +#ifdef CONFIG_UNIX98_PTYS +static struct file_operations ptmx_fops = { + .llseek = no_llseek, + .read = tty_read, + .write = tty_write, + .poll = tty_poll, + .ioctl = tty_ioctl, + .open = ptmx_open, + .release = tty_release, + .fasync = tty_fasync, +}; +#endif + +static struct file_operations console_fops = { + .llseek = no_llseek, + .read = tty_read, + .write = redirected_tty_write, + .poll = tty_poll, + .ioctl = tty_ioctl, + .open = tty_open, + .release = tty_release, + .fasync = tty_fasync, +}; + +static struct file_operations hung_up_tty_fops = { + .llseek = no_llseek, + .read = hung_up_tty_read, + .write = hung_up_tty_write, + .poll = hung_up_tty_poll, + .ioctl = hung_up_tty_ioctl, + .release = tty_release, +}; + +static DEFINE_SPINLOCK(redirect_lock); +static struct file *redirect; + +/** + * tty_wakeup - request more data + * @tty: terminal + * + * Internal and external helper for wakeups of tty. This function + * informs the line discipline if present that the driver is ready + * to receive more output data. + */ + +void tty_wakeup(struct tty_struct *tty) +{ + struct tty_ldisc *ld; + + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { + ld = tty_ldisc_ref(tty); + if(ld) { + if(ld->write_wakeup) + ld->write_wakeup(tty); + tty_ldisc_deref(ld); + } + } + wake_up_interruptible(&tty->write_wait); +} + +EXPORT_SYMBOL_GPL(tty_wakeup); + +/** + * tty_ldisc_flush - flush line discipline queue + * @tty: tty + * + * Flush the line discipline queue (if any) for this tty. If there + * is no line discipline active this is a no-op. + */ + +void tty_ldisc_flush(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if(ld) { + if(ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } +} + +EXPORT_SYMBOL_GPL(tty_ldisc_flush); + +/* + * This can be called by the "eventd" kernel thread. That is process synchronous, + * but doesn't hold any locks, so we need to make sure we have the appropriate + * locks for what we're doing.. + */ +static void do_tty_hangup(void *data) +{ + struct tty_struct *tty = (struct tty_struct *) data; + struct file * cons_filp = NULL; + struct file *filp, *f = NULL; + struct task_struct *p; + struct tty_ldisc *ld; + int closecount = 0, n; + + if (!tty) + return; + + /* inuse_filps is protected by the single kernel lock */ + lock_kernel(); + + spin_lock(&redirect_lock); + if (redirect && redirect->private_data == tty) { + f = redirect; + redirect = NULL; + } + spin_unlock(&redirect_lock); + + check_tty_count(tty, "do_tty_hangup"); + file_list_lock(); + /* This breaks for file handles being sent over AF_UNIX sockets ? */ + list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { + if (filp->f_op->write == redirected_tty_write) + cons_filp = filp; + if (filp->f_op->write != tty_write) + continue; + closecount++; + tty_fasync(-1, filp, 0); /* can't block */ + filp->f_op = &hung_up_tty_fops; + } + file_list_unlock(); + + /* FIXME! What are the locking issues here? This may me overdoing things.. + * this question is especially important now that we've removed the irqlock. */ + + ld = tty_ldisc_ref(tty); + if(ld != NULL) /* We may have no line discipline at this point */ + { + if (ld->flush_buffer) + ld->flush_buffer(tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && + ld->write_wakeup) + ld->write_wakeup(tty); + if (ld->hangup) + ld->hangup(tty); + } + + /* FIXME: Once we trust the LDISC code better we can wait here for + ldisc completion and fix the driver call race */ + + wake_up_interruptible(&tty->write_wait); + wake_up_interruptible(&tty->read_wait); + + /* + * Shutdown the current line discipline, and reset it to + * N_TTY. + */ + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) + { + down(&tty->termios_sem); + *tty->termios = tty->driver->init_termios; + up(&tty->termios_sem); + } + + /* Defer ldisc switch */ + /* tty_deferred_ldisc_switch(N_TTY); + + This should get done automatically when the port closes and + tty_release is called */ + + read_lock(&tasklist_lock); + if (tty->session > 0) { + do_each_task_pid(tty->session, PIDTYPE_SID, p) { + if (p->signal->tty == tty) + p->signal->tty = NULL; + if (!p->signal->leader) + continue; + send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p); + send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p); + if (tty->pgrp > 0) + p->signal->tty_old_pgrp = tty->pgrp; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); + } + read_unlock(&tasklist_lock); + + tty->flags = 0; + tty->session = 0; + tty->pgrp = -1; + tty->ctrl_status = 0; + /* + * If one of the devices matches a console pointer, we + * cannot just call hangup() because that will cause + * tty->count and state->count to go out of sync. + * So we just call close() the right number of times. + */ + if (cons_filp) { + if (tty->driver->close) + for (n = 0; n < closecount; n++) + tty->driver->close(tty, cons_filp); + } else if (tty->driver->hangup) + (tty->driver->hangup)(tty); + + /* We don't want to have driver/ldisc interactions beyond + the ones we did here. The driver layer expects no + calls after ->hangup() from the ldisc side. However we + can't yet guarantee all that */ + + set_bit(TTY_HUPPED, &tty->flags); + if (ld) { + tty_ldisc_enable(tty); + tty_ldisc_deref(ld); + } + unlock_kernel(); + if (f) + fput(f); +} + +void tty_hangup(struct tty_struct * tty) +{ +#ifdef TTY_DEBUG_HANGUP + char buf[64]; + + printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); +#endif + schedule_work(&tty->hangup_work); +} + +EXPORT_SYMBOL(tty_hangup); + +void tty_vhangup(struct tty_struct * tty) +{ +#ifdef TTY_DEBUG_HANGUP + char buf[64]; + + printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); +#endif + do_tty_hangup((void *) tty); +} +EXPORT_SYMBOL(tty_vhangup); + +int tty_hung_up_p(struct file * filp) +{ + return (filp->f_op == &hung_up_tty_fops); +} + +EXPORT_SYMBOL(tty_hung_up_p); + +/* + * This function is typically called only by the session leader, when + * it wants to disassociate itself from its controlling tty. + * + * It performs the following functions: + * (1) Sends a SIGHUP and SIGCONT to the foreground process group + * (2) Clears the tty from being controlling the session + * (3) Clears the controlling tty for all processes in the + * session group. + * + * The argument on_exit is set to 1 if called when a process is + * exiting; it is 0 if called by the ioctl TIOCNOTTY. + */ +void disassociate_ctty(int on_exit) +{ + struct tty_struct *tty; + struct task_struct *p; + int tty_pgrp = -1; + + lock_kernel(); + + down(&tty_sem); + tty = current->signal->tty; + if (tty) { + tty_pgrp = tty->pgrp; + up(&tty_sem); + if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) + tty_vhangup(tty); + } else { + if (current->signal->tty_old_pgrp) { + kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit); + kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit); + } + up(&tty_sem); + unlock_kernel(); + return; + } + if (tty_pgrp > 0) { + kill_pg(tty_pgrp, SIGHUP, on_exit); + if (!on_exit) + kill_pg(tty_pgrp, SIGCONT, on_exit); + } + + /* Must lock changes to tty_old_pgrp */ + down(&tty_sem); + current->signal->tty_old_pgrp = 0; + tty->session = 0; + tty->pgrp = -1; + + /* Now clear signal->tty under the lock */ + read_lock(&tasklist_lock); + do_each_task_pid(current->signal->session, PIDTYPE_SID, p) { + p->signal->tty = NULL; + } while_each_task_pid(current->signal->session, PIDTYPE_SID, p); + read_unlock(&tasklist_lock); + up(&tty_sem); + unlock_kernel(); +} + +void stop_tty(struct tty_struct *tty) +{ + if (tty->stopped) + return; + tty->stopped = 1; + if (tty->link && tty->link->packet) { + tty->ctrl_status &= ~TIOCPKT_START; + tty->ctrl_status |= TIOCPKT_STOP; + wake_up_interruptible(&tty->link->read_wait); + } + if (tty->driver->stop) + (tty->driver->stop)(tty); +} + +EXPORT_SYMBOL(stop_tty); + +void start_tty(struct tty_struct *tty) +{ + if (!tty->stopped || tty->flow_stopped) + return; + tty->stopped = 0; + if (tty->link && tty->link->packet) { + tty->ctrl_status &= ~TIOCPKT_STOP; + tty->ctrl_status |= TIOCPKT_START; + wake_up_interruptible(&tty->link->read_wait); + } + if (tty->driver->start) + (tty->driver->start)(tty); + + /* If we have a running line discipline it may need kicking */ + tty_wakeup(tty); + wake_up_interruptible(&tty->write_wait); +} + +EXPORT_SYMBOL(start_tty); + +static ssize_t tty_read(struct file * file, char __user * buf, size_t count, + loff_t *ppos) +{ + int i; + struct tty_struct * tty; + struct inode *inode; + struct tty_ldisc *ld; + + tty = (struct tty_struct *)file->private_data; + inode = file->f_dentry->d_inode; + if (tty_paranoia_check(tty, inode, "tty_read")) + return -EIO; + if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) + return -EIO; + + /* We want to wait for the line discipline to sort out in this + situation */ + ld = tty_ldisc_ref_wait(tty); + lock_kernel(); + if (ld->read) + i = (ld->read)(tty,file,buf,count); + else + i = -EIO; + tty_ldisc_deref(ld); + unlock_kernel(); + if (i > 0) + inode->i_atime = current_fs_time(inode->i_sb); + return i; +} + +/* + * Split writes up in sane blocksizes to avoid + * denial-of-service type attacks + */ +static inline ssize_t do_tty_write( + ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t), + struct tty_struct *tty, + struct file *file, + const char __user *buf, + size_t count) +{ + ssize_t ret = 0, written = 0; + unsigned int chunk; + + if (down_interruptible(&tty->atomic_write)) { + return -ERESTARTSYS; + } + + /* + * We chunk up writes into a temporary buffer. This + * simplifies low-level drivers immensely, since they + * don't have locking issues and user mode accesses. + * + * But if TTY_NO_WRITE_SPLIT is set, we should use a + * big chunk-size.. + * + * The default chunk-size is 2kB, because the NTTY + * layer has problems with bigger chunks. It will + * claim to be able to handle more characters than + * it actually does. + */ + chunk = 2048; + if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) + chunk = 65536; + if (count < chunk) + chunk = count; + + /* write_buf/write_cnt is protected by the atomic_write semaphore */ + if (tty->write_cnt < chunk) { + unsigned char *buf; + + if (chunk < 1024) + chunk = 1024; + + buf = kmalloc(chunk, GFP_KERNEL); + if (!buf) { + up(&tty->atomic_write); + return -ENOMEM; + } + kfree(tty->write_buf); + tty->write_cnt = chunk; + tty->write_buf = buf; + } + + /* Do the write .. */ + for (;;) { + size_t size = count; + if (size > chunk) + size = chunk; + ret = -EFAULT; + if (copy_from_user(tty->write_buf, buf, size)) + break; + lock_kernel(); + ret = write(tty, file, tty->write_buf, size); + unlock_kernel(); + if (ret <= 0) + break; + written += ret; + buf += ret; + count -= ret; + if (!count) + break; + ret = -ERESTARTSYS; + if (signal_pending(current)) + break; + cond_resched(); + } + if (written) { + struct inode *inode = file->f_dentry->d_inode; + inode->i_mtime = current_fs_time(inode->i_sb); + ret = written; + } + up(&tty->atomic_write); + return ret; +} + + +static ssize_t tty_write(struct file * file, const char __user * buf, size_t count, + loff_t *ppos) +{ + struct tty_struct * tty; + struct inode *inode = file->f_dentry->d_inode; + ssize_t ret; + struct tty_ldisc *ld; + + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode, "tty_write")) + return -EIO; + if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags))) + return -EIO; + + ld = tty_ldisc_ref_wait(tty); + if (!ld->write) + ret = -EIO; + else + ret = do_tty_write(ld->write, tty, file, buf, count); + tty_ldisc_deref(ld); + return ret; +} + +ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count, + loff_t *ppos) +{ + struct file *p = NULL; + + spin_lock(&redirect_lock); + if (redirect) { + get_file(redirect); + p = redirect; + } + spin_unlock(&redirect_lock); + + if (p) { + ssize_t res; + res = vfs_write(p, buf, count, &p->f_pos); + fput(p); + return res; + } + + return tty_write(file, buf, count, ppos); +} + +static char ptychar[] = "pqrstuvwxyzabcde"; + +static inline void pty_line_name(struct tty_driver *driver, int index, char *p) +{ + int i = index + driver->name_base; + /* ->name is initialized to "ttyp", but "tty" is expected */ + sprintf(p, "%s%c%x", + driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, + ptychar[i >> 4 & 0xf], i & 0xf); +} + +static inline void tty_line_name(struct tty_driver *driver, int index, char *p) +{ + sprintf(p, "%s%d", driver->name, index + driver->name_base); +} + +/* + * WSH 06/09/97: Rewritten to remove races and properly clean up after a + * failed open. The new code protects the open with a semaphore, so it's + * really quite straightforward. The semaphore locking can probably be + * relaxed for the (most common) case of reopening a tty. + */ +static int init_dev(struct tty_driver *driver, int idx, + struct tty_struct **ret_tty) +{ + struct tty_struct *tty, *o_tty; + struct termios *tp, **tp_loc, *o_tp, **o_tp_loc; + struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; + int retval=0; + + /* check whether we're reopening an existing tty */ + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tty = devpts_get_tty(idx); + if (tty && driver->subtype == PTY_TYPE_MASTER) + tty = tty->link; + } else { + tty = driver->ttys[idx]; + } + if (tty) goto fast_track; + + /* + * First time open is complex, especially for PTY devices. + * This code guarantees that either everything succeeds and the + * TTY is ready for operation, or else the table slots are vacated + * and the allocated memory released. (Except that the termios + * and locked termios may be retained.) + */ + + if (!try_module_get(driver->owner)) { + retval = -ENODEV; + goto end_init; + } + + o_tty = NULL; + tp = o_tp = NULL; + ltp = o_ltp = NULL; + + tty = alloc_tty_struct(); + if(!tty) + goto fail_no_mem; + initialize_tty_struct(tty); + tty->driver = driver; + tty->index = idx; + tty_line_name(driver, idx, tty->name); + + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tp_loc = &tty->termios; + ltp_loc = &tty->termios_locked; + } else { + tp_loc = &driver->termios[idx]; + ltp_loc = &driver->termios_locked[idx]; + } + + if (!*tp_loc) { + tp = (struct termios *) kmalloc(sizeof(struct termios), + GFP_KERNEL); + if (!tp) + goto free_mem_out; + *tp = driver->init_termios; + } + + if (!*ltp_loc) { + ltp = (struct termios *) kmalloc(sizeof(struct termios), + GFP_KERNEL); + if (!ltp) + goto free_mem_out; + memset(ltp, 0, sizeof(struct termios)); + } + + if (driver->type == TTY_DRIVER_TYPE_PTY) { + o_tty = alloc_tty_struct(); + if (!o_tty) + goto free_mem_out; + initialize_tty_struct(o_tty); + o_tty->driver = driver->other; + o_tty->index = idx; + tty_line_name(driver->other, idx, o_tty->name); + + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + o_tp_loc = &o_tty->termios; + o_ltp_loc = &o_tty->termios_locked; + } else { + o_tp_loc = &driver->other->termios[idx]; + o_ltp_loc = &driver->other->termios_locked[idx]; + } + + if (!*o_tp_loc) { + o_tp = (struct termios *) + kmalloc(sizeof(struct termios), GFP_KERNEL); + if (!o_tp) + goto free_mem_out; + *o_tp = driver->other->init_termios; + } + + if (!*o_ltp_loc) { + o_ltp = (struct termios *) + kmalloc(sizeof(struct termios), GFP_KERNEL); + if (!o_ltp) + goto free_mem_out; + memset(o_ltp, 0, sizeof(struct termios)); + } + + /* + * Everything allocated ... set up the o_tty structure. + */ + if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) { + driver->other->ttys[idx] = o_tty; + } + if (!*o_tp_loc) + *o_tp_loc = o_tp; + if (!*o_ltp_loc) + *o_ltp_loc = o_ltp; + o_tty->termios = *o_tp_loc; + o_tty->termios_locked = *o_ltp_loc; + driver->other->refcount++; + if (driver->subtype == PTY_TYPE_MASTER) + o_tty->count++; + + /* Establish the links in both directions */ + tty->link = o_tty; + o_tty->link = tty; + } + + /* + * All structures have been allocated, so now we install them. + * Failures after this point use release_mem to clean up, so + * there's no need to null out the local pointers. + */ + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + driver->ttys[idx] = tty; + } + + if (!*tp_loc) + *tp_loc = tp; + if (!*ltp_loc) + *ltp_loc = ltp; + tty->termios = *tp_loc; + tty->termios_locked = *ltp_loc; + driver->refcount++; + tty->count++; + + /* + * Structures all installed ... call the ldisc open routines. + * If we fail here just call release_mem to clean up. No need + * to decrement the use counts, as release_mem doesn't care. + */ + + if (tty->ldisc.open) { + retval = (tty->ldisc.open)(tty); + if (retval) + goto release_mem_out; + } + if (o_tty && o_tty->ldisc.open) { + retval = (o_tty->ldisc.open)(o_tty); + if (retval) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + goto release_mem_out; + } + tty_ldisc_enable(o_tty); + } + tty_ldisc_enable(tty); + goto success; + + /* + * This fast open can be used if the tty is already open. + * No memory is allocated, and the only failures are from + * attempting to open a closing tty or attempting multiple + * opens on a pty master. + */ +fast_track: + if (test_bit(TTY_CLOSING, &tty->flags)) { + retval = -EIO; + goto end_init; + } + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER) { + /* + * special case for PTY masters: only one open permitted, + * and the slave side open count is incremented as well. + */ + if (tty->count) { + retval = -EIO; + goto end_init; + } + tty->link->count++; + } + tty->count++; + tty->driver = driver; /* N.B. why do this every time?? */ + + /* FIXME */ + if(!test_bit(TTY_LDISC, &tty->flags)) + printk(KERN_ERR "init_dev but no ldisc\n"); +success: + *ret_tty = tty; + + /* All paths come through here to release the semaphore */ +end_init: + return retval; + + /* Release locally allocated memory ... nothing placed in slots */ +free_mem_out: + kfree(o_tp); + if (o_tty) + free_tty_struct(o_tty); + kfree(ltp); + kfree(tp); + free_tty_struct(tty); + +fail_no_mem: + module_put(driver->owner); + retval = -ENOMEM; + goto end_init; + + /* call the tty release_mem routine to clean out this slot */ +release_mem_out: + printk(KERN_INFO "init_dev: ldisc open failed, " + "clearing slot %d\n", idx); + release_mem(tty, idx); + goto end_init; +} + +/* + * Releases memory associated with a tty structure, and clears out the + * driver table slots. + */ +static void release_mem(struct tty_struct *tty, int idx) +{ + struct tty_struct *o_tty; + struct termios *tp; + int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; + + if ((o_tty = tty->link) != NULL) { + if (!devpts) + o_tty->driver->ttys[idx] = NULL; + if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { + tp = o_tty->termios; + if (!devpts) + o_tty->driver->termios[idx] = NULL; + kfree(tp); + + tp = o_tty->termios_locked; + if (!devpts) + o_tty->driver->termios_locked[idx] = NULL; + kfree(tp); + } + o_tty->magic = 0; + o_tty->driver->refcount--; + file_list_lock(); + list_del_init(&o_tty->tty_files); + file_list_unlock(); + free_tty_struct(o_tty); + } + + if (!devpts) + tty->driver->ttys[idx] = NULL; + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { + tp = tty->termios; + if (!devpts) + tty->driver->termios[idx] = NULL; + kfree(tp); + + tp = tty->termios_locked; + if (!devpts) + tty->driver->termios_locked[idx] = NULL; + kfree(tp); + } + + tty->magic = 0; + tty->driver->refcount--; + file_list_lock(); + list_del_init(&tty->tty_files); + file_list_unlock(); + module_put(tty->driver->owner); + free_tty_struct(tty); +} + +/* + * Even releasing the tty structures is a tricky business.. We have + * to be very careful that the structures are all released at the + * same time, as interrupts might otherwise get the wrong pointers. + * + * WSH 09/09/97: rewritten to avoid some nasty race conditions that could + * lead to double frees or releasing memory still in use. + */ +static void release_dev(struct file * filp) +{ + struct tty_struct *tty, *o_tty; + int pty_master, tty_closing, o_tty_closing, do_sleep; + int devpts_master, devpts; + int idx; + char buf[64]; + unsigned long flags; + + tty = (struct tty_struct *)filp->private_data; + if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev")) + return; + + check_tty_count(tty, "release_dev"); + + tty_fasync(-1, filp, 0); + + idx = tty->index; + pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER); + devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; + devpts_master = pty_master && devpts; + o_tty = tty->link; + +#ifdef TTY_PARANOIA_CHECK + if (idx < 0 || idx >= tty->driver->num) { + printk(KERN_DEBUG "release_dev: bad idx when trying to " + "free (%s)\n", tty->name); + return; + } + if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + if (tty != tty->driver->ttys[idx]) { + printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " + "for (%s)\n", idx, tty->name); + return; + } + if (tty->termios != tty->driver->termios[idx]) { + printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " + "for (%s)\n", + idx, tty->name); + return; + } + if (tty->termios_locked != tty->driver->termios_locked[idx]) { + printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " + "termios_locked for (%s)\n", + idx, tty->name); + return; + } + } +#endif + +#ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", + tty_name(tty, buf), tty->count); +#endif + +#ifdef TTY_PARANOIA_CHECK + if (tty->driver->other && + !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + if (o_tty != tty->driver->other->ttys[idx]) { + printk(KERN_DEBUG "release_dev: other->table[%d] " + "not o_tty for (%s)\n", + idx, tty->name); + return; + } + if (o_tty->termios != tty->driver->other->termios[idx]) { + printk(KERN_DEBUG "release_dev: other->termios[%d] " + "not o_termios for (%s)\n", + idx, tty->name); + return; + } + if (o_tty->termios_locked != + tty->driver->other->termios_locked[idx]) { + printk(KERN_DEBUG "release_dev: other->termios_locked[" + "%d] not o_termios_locked for (%s)\n", + idx, tty->name); + return; + } + if (o_tty->link != tty) { + printk(KERN_DEBUG "release_dev: bad pty pointers\n"); + return; + } + } +#endif + if (tty->driver->close) + tty->driver->close(tty, filp); + + /* + * Sanity check: if tty->count is going to zero, there shouldn't be + * any waiters on tty->read_wait or tty->write_wait. We test the + * wait queues and kick everyone out _before_ actually starting to + * close. This ensures that we won't block while releasing the tty + * structure. + * + * The test for the o_tty closing is necessary, since the master and + * slave sides may close in any order. If the slave side closes out + * first, its count will be one, since the master side holds an open. + * Thus this test wouldn't be triggered at the time the slave closes, + * so we do it now. + * + * Note that it's possible for the tty to be opened again while we're + * flushing out waiters. By recalculating the closing flags before + * each iteration we avoid any problems. + */ + while (1) { + /* Guard against races with tty->count changes elsewhere and + opens on /dev/tty */ + + down(&tty_sem); + tty_closing = tty->count <= 1; + o_tty_closing = o_tty && + (o_tty->count <= (pty_master ? 1 : 0)); + do_sleep = 0; + + if (tty_closing) { + if (waitqueue_active(&tty->read_wait)) { + wake_up(&tty->read_wait); + do_sleep++; + } + if (waitqueue_active(&tty->write_wait)) { + wake_up(&tty->write_wait); + do_sleep++; + } + } + if (o_tty_closing) { + if (waitqueue_active(&o_tty->read_wait)) { + wake_up(&o_tty->read_wait); + do_sleep++; + } + if (waitqueue_active(&o_tty->write_wait)) { + wake_up(&o_tty->write_wait); + do_sleep++; + } + } + if (!do_sleep) + break; + + printk(KERN_WARNING "release_dev: %s: read/write wait queue " + "active!\n", tty_name(tty, buf)); + up(&tty_sem); + schedule(); + } + + /* + * The closing flags are now consistent with the open counts on + * both sides, and we've completed the last operation that could + * block, so it's safe to proceed with closing. + */ + if (pty_master) { + if (--o_tty->count < 0) { + printk(KERN_WARNING "release_dev: bad pty slave count " + "(%d) for %s\n", + o_tty->count, tty_name(o_tty, buf)); + o_tty->count = 0; + } + } + if (--tty->count < 0) { + printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", + tty->count, tty_name(tty, buf)); + tty->count = 0; + } + + /* + * We've decremented tty->count, so we need to remove this file + * descriptor off the tty->tty_files list; this serves two + * purposes: + * - check_tty_count sees the correct number of file descriptors + * associated with this tty. + * - do_tty_hangup no longer sees this file descriptor as + * something that needs to be handled for hangups. + */ + file_kill(filp); + filp->private_data = NULL; + + /* + * Perform some housekeeping before deciding whether to return. + * + * Set the TTY_CLOSING flag if this was the last open. In the + * case of a pty we may have to wait around for the other side + * to close, and TTY_CLOSING makes sure we can't be reopened. + */ + if(tty_closing) + set_bit(TTY_CLOSING, &tty->flags); + if(o_tty_closing) + set_bit(TTY_CLOSING, &o_tty->flags); + + /* + * If _either_ side is closing, make sure there aren't any + * processes that still think tty or o_tty is their controlling + * tty. + */ + if (tty_closing || o_tty_closing) { + struct task_struct *p; + + read_lock(&tasklist_lock); + do_each_task_pid(tty->session, PIDTYPE_SID, p) { + p->signal->tty = NULL; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); + if (o_tty) + do_each_task_pid(o_tty->session, PIDTYPE_SID, p) { + p->signal->tty = NULL; + } while_each_task_pid(o_tty->session, PIDTYPE_SID, p); + read_unlock(&tasklist_lock); + } + + up(&tty_sem); + + /* check whether both sides are closing ... */ + if (!tty_closing || (o_tty && !o_tty_closing)) + return; + +#ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "freeing tty structure..."); +#endif + /* + * Prevent flush_to_ldisc() from rescheduling the work for later. Then + * kill any delayed work. As this is the final close it does not + * race with the set_ldisc code path. + */ + clear_bit(TTY_LDISC, &tty->flags); + clear_bit(TTY_DONT_FLIP, &tty->flags); + cancel_delayed_work(&tty->buf.work); + + /* + * Wait for ->hangup_work and ->buf.work handlers to terminate + */ + + flush_scheduled_work(); + + /* + * Wait for any short term users (we know they are just driver + * side waiters as the file is closing so user count on the file + * side is zero. + */ + spin_lock_irqsave(&tty_ldisc_lock, flags); + while(tty->ldisc.refcount) + { + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0); + spin_lock_irqsave(&tty_ldisc_lock, flags); + } + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + /* + * Shutdown the current line discipline, and reset it to N_TTY. + * N.B. why reset ldisc when we're releasing the memory?? + * + * FIXME: this MUST get fixed for the new reflocking + */ + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty_ldisc_put(tty->ldisc.num); + + /* + * Switch the line discipline back + */ + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(tty,N_TTY); + if (o_tty) { + /* FIXME: could o_tty be in setldisc here ? */ + clear_bit(TTY_LDISC, &o_tty->flags); + if (o_tty->ldisc.close) + (o_tty->ldisc.close)(o_tty); + tty_ldisc_put(o_tty->ldisc.num); + tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY)); + tty_set_termios_ldisc(o_tty,N_TTY); + } + /* + * The release_mem function takes care of the details of clearing + * the slots and preserving the termios structure. + */ + release_mem(tty, idx); + +#ifdef CONFIG_UNIX98_PTYS + /* Make this pty number available for reallocation */ + if (devpts) { + down(&allocated_ptys_lock); + idr_remove(&allocated_ptys, idx); + up(&allocated_ptys_lock); + } +#endif + +} + +/* + * tty_open and tty_release keep up the tty count that contains the + * number of opens done on a tty. We cannot use the inode-count, as + * different inodes might point to the same tty. + * + * Open-counting is needed for pty masters, as well as for keeping + * track of serial lines: DTR is dropped when the last close happens. + * (This is not done solely through tty->count, now. - Ted 1/27/92) + * + * The termios state of a pty is reset on first open so that + * settings don't persist across reuse. + */ +static int tty_open(struct inode * inode, struct file * filp) +{ + struct tty_struct *tty; + int noctty, retval; + struct tty_driver *driver; + int index; + dev_t device = inode->i_rdev; + unsigned short saved_flags = filp->f_flags; + + nonseekable_open(inode, filp); + +retry_open: + noctty = filp->f_flags & O_NOCTTY; + index = -1; + retval = 0; + + down(&tty_sem); + + if (device == MKDEV(TTYAUX_MAJOR,0)) { + if (!current->signal->tty) { + up(&tty_sem); + return -ENXIO; + } + driver = current->signal->tty->driver; + index = current->signal->tty->index; + filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ + /* noctty = 1; */ + goto got_driver; + } +#ifdef CONFIG_VT + if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) { + extern struct tty_driver *console_driver; + driver = console_driver; + index = fg_console; + noctty = 1; + goto got_driver; + } +#endif + if (device == MKDEV(TTYAUX_MAJOR,1)) { + driver = console_device(&index); + if (driver) { + /* Don't let /dev/console block */ + filp->f_flags |= O_NONBLOCK; + noctty = 1; + goto got_driver; + } + up(&tty_sem); + return -ENODEV; + } + + driver = get_tty_driver(device, &index); + if (!driver) { + up(&tty_sem); + return -ENODEV; + } +got_driver: + retval = init_dev(driver, index, &tty); + up(&tty_sem); + if (retval) + return retval; + + filp->private_data = tty; + file_move(filp, &tty->tty_files); + check_tty_count(tty, "tty_open"); + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER) + noctty = 1; +#ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "opening %s...", tty->name); +#endif + if (!retval) { + if (tty->driver->open) + retval = tty->driver->open(tty, filp); + else + retval = -ENODEV; + } + filp->f_flags = saved_flags; + + if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) + retval = -EBUSY; + + if (retval) { +#ifdef TTY_DEBUG_HANGUP + printk(KERN_DEBUG "error %d in opening %s...", retval, + tty->name); +#endif + release_dev(filp); + if (retval != -ERESTARTSYS) + return retval; + if (signal_pending(current)) + return retval; + schedule(); + /* + * Need to reset f_op in case a hangup happened. + */ + if (filp->f_op == &hung_up_tty_fops) + filp->f_op = &tty_fops; + goto retry_open; + } + if (!noctty && + current->signal->leader && + !current->signal->tty && + tty->session == 0) { + task_lock(current); + current->signal->tty = tty; + task_unlock(current); + current->signal->tty_old_pgrp = 0; + tty->session = current->signal->session; + tty->pgrp = process_group(current); + } + return 0; +} + +#ifdef CONFIG_UNIX98_PTYS +static int ptmx_open(struct inode * inode, struct file * filp) +{ + struct tty_struct *tty; + int retval; + int index; + int idr_ret; + + nonseekable_open(inode, filp); + + /* find a device that is not in use. */ + down(&allocated_ptys_lock); + if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { + up(&allocated_ptys_lock); + return -ENOMEM; + } + idr_ret = idr_get_new(&allocated_ptys, NULL, &index); + if (idr_ret < 0) { + up(&allocated_ptys_lock); + if (idr_ret == -EAGAIN) + return -ENOMEM; + return -EIO; + } + if (index >= pty_limit) { + idr_remove(&allocated_ptys, index); + up(&allocated_ptys_lock); + return -EIO; + } + up(&allocated_ptys_lock); + + down(&tty_sem); + retval = init_dev(ptm_driver, index, &tty); + up(&tty_sem); + + if (retval) + goto out; + + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + filp->private_data = tty; + file_move(filp, &tty->tty_files); + + retval = -ENOMEM; + if (devpts_pty_new(tty->link)) + goto out1; + + check_tty_count(tty, "tty_open"); + retval = ptm_driver->open(tty, filp); + if (!retval) + return 0; +out1: + release_dev(filp); +out: + down(&allocated_ptys_lock); + idr_remove(&allocated_ptys, index); + up(&allocated_ptys_lock); + return retval; +} +#endif + +static int tty_release(struct inode * inode, struct file * filp) +{ + lock_kernel(); + release_dev(filp); + unlock_kernel(); + return 0; +} + +/* No kernel lock held - fine */ +static unsigned int tty_poll(struct file * filp, poll_table * wait) +{ + struct tty_struct * tty; + struct tty_ldisc *ld; + int ret = 0; + + tty = (struct tty_struct *)filp->private_data; + if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll")) + return 0; + + ld = tty_ldisc_ref_wait(tty); + if (ld->poll) + ret = (ld->poll)(tty, filp, wait); + tty_ldisc_deref(ld); + return ret; +} + +static int tty_fasync(int fd, struct file * filp, int on) +{ + struct tty_struct * tty; + int retval; + + tty = (struct tty_struct *)filp->private_data; + if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_fasync")) + return 0; + + retval = fasync_helper(fd, filp, on, &tty->fasync); + if (retval <= 0) + return retval; + + if (on) { + if (!waitqueue_active(&tty->read_wait)) + tty->minimum_to_wake = 1; + retval = f_setown(filp, (-tty->pgrp) ? : current->pid, 0); + if (retval) + return retval; + } else { + if (!tty->fasync && !waitqueue_active(&tty->read_wait)) + tty->minimum_to_wake = N_TTY_BUF_SIZE; + } + return 0; +} + +static int tiocsti(struct tty_struct *tty, char __user *p) +{ + char ch, mbz = 0; + struct tty_ldisc *ld; + + if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(ch, p)) + return -EFAULT; + ld = tty_ldisc_ref_wait(tty); + ld->receive_buf(tty, &ch, &mbz, 1); + tty_ldisc_deref(ld); + return 0; +} + +static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg) +{ + if (copy_to_user(arg, &tty->winsize, sizeof(*arg))) + return -EFAULT; + return 0; +} + +static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize __user * arg) +{ + struct winsize tmp_ws; + + if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) + return -EFAULT; + if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) + return 0; +#ifdef CONFIG_VT + if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { + int rc; + + acquire_console_sem(); + rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row); + release_console_sem(); + if (rc) + return -ENXIO; + } +#endif + if (tty->pgrp > 0) + kill_pg(tty->pgrp, SIGWINCH, 1); + if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0)) + kill_pg(real_tty->pgrp, SIGWINCH, 1); + tty->winsize = tmp_ws; + real_tty->winsize = tmp_ws; + return 0; +} + +static int tioccons(struct file *file) +{ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (file->f_op->write == redirected_tty_write) { + struct file *f; + spin_lock(&redirect_lock); + f = redirect; + redirect = NULL; + spin_unlock(&redirect_lock); + if (f) + fput(f); + return 0; + } + spin_lock(&redirect_lock); + if (redirect) { + spin_unlock(&redirect_lock); + return -EBUSY; + } + get_file(file); + redirect = file; + spin_unlock(&redirect_lock); + return 0; +} + + +static int fionbio(struct file *file, int __user *p) +{ + int nonblock; + + if (get_user(nonblock, p)) + return -EFAULT; + + if (nonblock) + file->f_flags |= O_NONBLOCK; + else + file->f_flags &= ~O_NONBLOCK; + return 0; +} + +static int tiocsctty(struct tty_struct *tty, int arg) +{ + task_t *p; + + if (current->signal->leader && + (current->signal->session == tty->session)) + return 0; + /* + * The process must be a session leader and + * not have a controlling tty already. + */ + if (!current->signal->leader || current->signal->tty) + return -EPERM; + if (tty->session > 0) { + /* + * This tty is already the controlling + * tty for another session group! + */ + if ((arg == 1) && capable(CAP_SYS_ADMIN)) { + /* + * Steal it away + */ + + read_lock(&tasklist_lock); + do_each_task_pid(tty->session, PIDTYPE_SID, p) { + p->signal->tty = NULL; + } while_each_task_pid(tty->session, PIDTYPE_SID, p); + read_unlock(&tasklist_lock); + } else + return -EPERM; + } + task_lock(current); + current->signal->tty = tty; + task_unlock(current); + current->signal->tty_old_pgrp = 0; + tty->session = current->signal->session; + tty->pgrp = process_group(current); + return 0; +} + +static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) +{ + /* + * (tty == real_tty) is a cheap way of + * testing if the tty is NOT a master pty. + */ + if (tty == real_tty && current->signal->tty != real_tty) + return -ENOTTY; + return put_user(real_tty->pgrp, p); +} + +static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) +{ + pid_t pgrp; + int retval = tty_check_change(real_tty); + + if (retval == -EIO) + return -ENOTTY; + if (retval) + return retval; + if (!current->signal->tty || + (current->signal->tty != real_tty) || + (real_tty->session != current->signal->session)) + return -ENOTTY; + if (get_user(pgrp, p)) + return -EFAULT; + if (pgrp < 0) + return -EINVAL; + if (session_of_pgrp(pgrp) != current->signal->session) + return -EPERM; + real_tty->pgrp = pgrp; + return 0; +} + +static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) +{ + /* + * (tty == real_tty) is a cheap way of + * testing if the tty is NOT a master pty. + */ + if (tty == real_tty && current->signal->tty != real_tty) + return -ENOTTY; + if (real_tty->session <= 0) + return -ENOTTY; + return put_user(real_tty->session, p); +} + +static int tiocsetd(struct tty_struct *tty, int __user *p) +{ + int ldisc; + + if (get_user(ldisc, p)) + return -EFAULT; + return tty_set_ldisc(tty, ldisc); +} + +static int send_break(struct tty_struct *tty, unsigned int duration) +{ + tty->driver->break_ctl(tty, -1); + if (!signal_pending(current)) { + msleep_interruptible(duration); + } + tty->driver->break_ctl(tty, 0); + if (signal_pending(current)) + return -EINTR; + return 0; +} + +static int +tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p) +{ + int retval = -EINVAL; + + if (tty->driver->tiocmget) { + retval = tty->driver->tiocmget(tty, file); + + if (retval >= 0) + retval = put_user(retval, p); + } + return retval; +} + +static int +tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd, + unsigned __user *p) +{ + int retval = -EINVAL; + + if (tty->driver->tiocmset) { + unsigned int set, clear, val; + + retval = get_user(val, p); + if (retval) + return retval; + + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = val; + break; + case TIOCMBIC: + clear = val; + break; + case TIOCMSET: + set = val; + clear = ~val; + break; + } + + set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; + clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; + + retval = tty->driver->tiocmset(tty, file, set, clear); + } + return retval; +} + +/* + * Split this up, as gcc can choke on it otherwise.. + */ +int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct tty_struct *tty, *real_tty; + void __user *p = (void __user *)arg; + int retval; + struct tty_ldisc *ld; + + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode, "tty_ioctl")) + return -EINVAL; + + real_tty = tty; + if (tty->driver->type == TTY_DRIVER_TYPE_PTY && + tty->driver->subtype == PTY_TYPE_MASTER) + real_tty = tty->link; + + /* + * Break handling by driver + */ + if (!tty->driver->break_ctl) { + switch(cmd) { + case TIOCSBRK: + case TIOCCBRK: + if (tty->driver->ioctl) + return tty->driver->ioctl(tty, file, cmd, arg); + return -EINVAL; + + /* These two ioctl's always return success; even if */ + /* the driver doesn't support them. */ + case TCSBRK: + case TCSBRKP: + if (!tty->driver->ioctl) + return 0; + retval = tty->driver->ioctl(tty, file, cmd, arg); + if (retval == -ENOIOCTLCMD) + retval = 0; + return retval; + } + } + + /* + * Factor out some common prep work + */ + switch (cmd) { + case TIOCSETD: + case TIOCSBRK: + case TIOCCBRK: + case TCSBRK: + case TCSBRKP: + retval = tty_check_change(tty); + if (retval) + return retval; + if (cmd != TIOCCBRK) { + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + } + break; + } + + switch (cmd) { + case TIOCSTI: + return tiocsti(tty, p); + case TIOCGWINSZ: + return tiocgwinsz(tty, p); + case TIOCSWINSZ: + return tiocswinsz(tty, real_tty, p); + case TIOCCONS: + return real_tty!=tty ? -EINVAL : tioccons(file); + case FIONBIO: + return fionbio(file, p); + case TIOCEXCL: + set_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNXCL: + clear_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNOTTY: + if (current->signal->tty != tty) + return -ENOTTY; + if (current->signal->leader) + disassociate_ctty(0); + task_lock(current); + current->signal->tty = NULL; + task_unlock(current); + return 0; + case TIOCSCTTY: + return tiocsctty(tty, arg); + case TIOCGPGRP: + return tiocgpgrp(tty, real_tty, p); + case TIOCSPGRP: + return tiocspgrp(tty, real_tty, p); + case TIOCGSID: + return tiocgsid(tty, real_tty, p); + case TIOCGETD: + /* FIXME: check this is ok */ + return put_user(tty->ldisc.num, (int __user *)p); + case TIOCSETD: + return tiocsetd(tty, p); +#ifdef CONFIG_VT + case TIOCLINUX: + return tioclinux(tty, arg); +#endif + /* + * Break handling + */ + case TIOCSBRK: /* Turn break on, unconditionally */ + tty->driver->break_ctl(tty, -1); + return 0; + + case TIOCCBRK: /* Turn break off, unconditionally */ + tty->driver->break_ctl(tty, 0); + return 0; + case TCSBRK: /* SVID version: non-zero arg --> no break */ + /* + * XXX is the above comment correct, or the + * code below correct? Is this ioctl used at + * all by anyone? + */ + if (!arg) + return send_break(tty, 250); + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + return send_break(tty, arg ? arg*100 : 250); + + case TIOCMGET: + return tty_tiocmget(tty, file, p); + + case TIOCMSET: + case TIOCMBIC: + case TIOCMBIS: + return tty_tiocmset(tty, file, cmd, p); + } + if (tty->driver->ioctl) { + retval = (tty->driver->ioctl)(tty, file, cmd, arg); + if (retval != -ENOIOCTLCMD) + return retval; + } + ld = tty_ldisc_ref_wait(tty); + retval = -EINVAL; + if (ld->ioctl) { + retval = ld->ioctl(tty, file, cmd, arg); + if (retval == -ENOIOCTLCMD) + retval = -EINVAL; + } + tty_ldisc_deref(ld); + return retval; +} + + +/* + * This implements the "Secure Attention Key" --- the idea is to + * prevent trojan horses by killing all processes associated with this + * tty when the user hits the "Secure Attention Key". Required for + * super-paranoid applications --- see the Orange Book for more details. + * + * This code could be nicer; ideally it should send a HUP, wait a few + * seconds, then send a INT, and then a KILL signal. But you then + * have to coordinate with the init process, since all processes associated + * with the current tty must be dead before the new getty is allowed + * to spawn. + * + * Now, if it would be correct ;-/ The current code has a nasty hole - + * it doesn't catch files in flight. We may send the descriptor to ourselves + * via AF_UNIX socket, close it and later fetch from socket. FIXME. + * + * Nasty bug: do_SAK is being called in interrupt context. This can + * deadlock. We punt it up to process context. AKPM - 16Mar2001 + */ +static void __do_SAK(void *arg) +{ +#ifdef TTY_SOFT_SAK + tty_hangup(tty); +#else + struct tty_struct *tty = arg; + struct task_struct *p; + int session; + int i; + struct file *filp; + struct tty_ldisc *disc; + struct fdtable *fdt; + + if (!tty) + return; + session = tty->session; + + /* We don't want an ldisc switch during this */ + disc = tty_ldisc_ref(tty); + if (disc && disc->flush_buffer) + disc->flush_buffer(tty); + tty_ldisc_deref(disc); + + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + + read_lock(&tasklist_lock); + do_each_task_pid(session, PIDTYPE_SID, p) { + if (p->signal->tty == tty || session > 0) { + printk(KERN_NOTICE "SAK: killed process %d" + " (%s): p->signal->session==tty->session\n", + p->pid, p->comm); + send_sig(SIGKILL, p, 1); + continue; + } + task_lock(p); + if (p->files) { + /* + * We don't take a ref to the file, so we must + * hold ->file_lock instead. + */ + spin_lock(&p->files->file_lock); + fdt = files_fdtable(p->files); + for (i=0; i < fdt->max_fds; i++) { + filp = fcheck_files(p->files, i); + if (!filp) + continue; + if (filp->f_op->read == tty_read && + filp->private_data == tty) { + printk(KERN_NOTICE "SAK: killed process %d" + " (%s): fd#%d opened to the tty\n", + p->pid, p->comm, i); + send_sig(SIGKILL, p, 1); + break; + } + } + spin_unlock(&p->files->file_lock); + } + task_unlock(p); + } while_each_task_pid(session, PIDTYPE_SID, p); + read_unlock(&tasklist_lock); +#endif +} + +/* + * The tq handling here is a little racy - tty->SAK_work may already be queued. + * Fortunately we don't need to worry, because if ->SAK_work is already queued, + * the values which we write to it will be identical to the values which it + * already has. --akpm + */ +void do_SAK(struct tty_struct *tty) +{ + if (!tty) + return; + PREPARE_WORK(&tty->SAK_work, __do_SAK, tty); + schedule_work(&tty->SAK_work); +} + +EXPORT_SYMBOL(do_SAK); + +/* + * This routine is called out of the software interrupt to flush data + * from the buffer chain to the line discipline. + */ + +static void flush_to_ldisc(void *private_) +{ + struct tty_struct *tty = (struct tty_struct *) private_; + unsigned long flags; + struct tty_ldisc *disc; + struct tty_buffer *tbuf, *head; + int count; + char *char_buf; + unsigned char *flag_buf; + + disc = tty_ldisc_ref(tty); + if (disc == NULL) /* !TTY_LDISC */ + return; + + if (test_bit(TTY_DONT_FLIP, &tty->flags)) { + /* + * Do it after the next timer tick: + */ + schedule_delayed_work(&tty->buf.work, 1); + goto out; + } + spin_lock_irqsave(&tty->buf.lock, flags); + head = tty->buf.head; + tty->buf.head = NULL; + while((tbuf = head) != NULL) { + while ((count = tbuf->commit - tbuf->read) != 0) { + char_buf = tbuf->char_buf_ptr + tbuf->read; + flag_buf = tbuf->flag_buf_ptr + tbuf->read; + tbuf->read += count; + spin_unlock_irqrestore(&tty->buf.lock, flags); + disc->receive_buf(tty, char_buf, flag_buf, count); + spin_lock_irqsave(&tty->buf.lock, flags); + } + if (tbuf->active) { + tty->buf.head = head; + break; + } + head = tbuf->next; + if (head == NULL) + tty->buf.tail = NULL; + tty_buffer_free(tty, tbuf); + } + spin_unlock_irqrestore(&tty->buf.lock, flags); +out: + tty_ldisc_deref(disc); +} + +/* + * Routine which returns the baud rate of the tty + * + * Note that the baud_table needs to be kept in sync with the + * include/asm/termbits.h file. + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 230400, 460800, +#ifdef __sparc__ + 76800, 153600, 307200, 614400, 921600 +#else + 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, + 2500000, 3000000, 3500000, 4000000 +#endif +}; + +static int n_baud_table = ARRAY_SIZE(baud_table); + +/** + * tty_termios_baud_rate + * @termios: termios structure + * + * Convert termios baud rate data into a speed. This should be called + * with the termios lock held if this termios is a terminal termios + * structure. May change the termios data. + */ + +int tty_termios_baud_rate(struct termios *termios) +{ + unsigned int cbaud; + + cbaud = termios->c_cflag & CBAUD; + + if (cbaud & CBAUDEX) { + cbaud &= ~CBAUDEX; + + if (cbaud < 1 || cbaud + 15 > n_baud_table) + termios->c_cflag &= ~CBAUDEX; + else + cbaud += 15; + } + return baud_table[cbaud]; +} + +EXPORT_SYMBOL(tty_termios_baud_rate); + +/** + * tty_get_baud_rate - get tty bit rates + * @tty: tty to query + * + * Returns the baud rate as an integer for this terminal. The + * termios lock must be held by the caller and the terminal bit + * flags may be updated. + */ + +int tty_get_baud_rate(struct tty_struct *tty) +{ + int baud = tty_termios_baud_rate(tty->termios); + + if (baud == 38400 && tty->alt_speed) { + if (!tty->warned) { + printk(KERN_WARNING "Use of setserial/setrocket to " + "set SPD_* flags is deprecated\n"); + tty->warned = 1; + } + baud = tty->alt_speed; + } + + return baud; +} + +EXPORT_SYMBOL(tty_get_baud_rate); + +/** + * tty_flip_buffer_push - terminal + * @tty: tty to push + * + * Queue a push of the terminal flip buffers to the line discipline. This + * function must not be called from IRQ context if tty->low_latency is set. + * + * In the event of the queue being busy for flipping the work will be + * held off and retried later. + */ + +void tty_flip_buffer_push(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) { + tty->buf.tail->active = 0; + tty->buf.tail->commit = tty->buf.tail->used; + } + spin_unlock_irqrestore(&tty->buf.lock, flags); + + if (tty->low_latency) + flush_to_ldisc((void *) tty); + else + schedule_delayed_work(&tty->buf.work, 1); +} + +EXPORT_SYMBOL(tty_flip_buffer_push); + + +/* + * This subroutine initializes a tty structure. + */ +static void initialize_tty_struct(struct tty_struct *tty) +{ + memset(tty, 0, sizeof(struct tty_struct)); + tty->magic = TTY_MAGIC; + tty_ldisc_assign(tty, tty_ldisc_get(N_TTY)); + tty->pgrp = -1; + tty->overrun_time = jiffies; + tty->buf.head = tty->buf.tail = NULL; + tty_buffer_init(tty); + INIT_WORK(&tty->buf.work, flush_to_ldisc, tty); + init_MUTEX(&tty->buf.pty_sem); + init_MUTEX(&tty->termios_sem); + init_waitqueue_head(&tty->write_wait); + init_waitqueue_head(&tty->read_wait); + INIT_WORK(&tty->hangup_work, do_tty_hangup, tty); + sema_init(&tty->atomic_read, 1); + sema_init(&tty->atomic_write, 1); + spin_lock_init(&tty->read_lock); + INIT_LIST_HEAD(&tty->tty_files); + INIT_WORK(&tty->SAK_work, NULL, NULL); +} + +/* + * The default put_char routine if the driver did not define one. + */ +static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) +{ + tty->driver->write(tty, &ch, 1); +} + +static struct class *tty_class; + +/** + * tty_register_device - register a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * @device: a struct device that is associated with this tty device. + * This field is optional, if there is no known struct device for this + * tty device it can be set to NULL safely. + * + * This call is required to be made to register an individual tty device if + * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that + * bit is not set, this function should not be called. + */ +void tty_register_device(struct tty_driver *driver, unsigned index, + struct device *device) +{ + char name[64]; + dev_t dev = MKDEV(driver->major, driver->minor_start) + index; + + if (index >= driver->num) { + printk(KERN_ERR "Attempt to register invalid tty line number " + " (%d).\n", index); + return; + } + + devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, + "%s%d", driver->devfs_name, index + driver->name_base); + + if (driver->type == TTY_DRIVER_TYPE_PTY) + pty_line_name(driver, index, name); + else + tty_line_name(driver, index, name); + class_device_create(tty_class, NULL, dev, device, "%s", name); +} + +/** + * tty_unregister_device - unregister a tty device + * @driver: the tty driver that describes the tty device + * @index: the index in the tty driver for this tty device + * + * If a tty device is registered with a call to tty_register_device() then + * this function must be made when the tty device is gone. + */ +void tty_unregister_device(struct tty_driver *driver, unsigned index) +{ + devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); + class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); +} + +EXPORT_SYMBOL(tty_register_device); +EXPORT_SYMBOL(tty_unregister_device); + +struct tty_driver *alloc_tty_driver(int lines) +{ + struct tty_driver *driver; + + driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL); + if (driver) { + memset(driver, 0, sizeof(struct tty_driver)); + driver->magic = TTY_DRIVER_MAGIC; + driver->num = lines; + /* later we'll move allocation of tables here */ + } + return driver; +} + +void put_tty_driver(struct tty_driver *driver) +{ + kfree(driver); +} + +void tty_set_operations(struct tty_driver *driver, struct tty_operations *op) +{ + driver->open = op->open; + driver->close = op->close; + driver->write = op->write; + driver->put_char = op->put_char; + driver->flush_chars = op->flush_chars; + driver->write_room = op->write_room; + driver->chars_in_buffer = op->chars_in_buffer; + driver->ioctl = op->ioctl; + driver->set_termios = op->set_termios; + driver->throttle = op->throttle; + driver->unthrottle = op->unthrottle; + driver->stop = op->stop; + driver->start = op->start; + driver->hangup = op->hangup; + driver->break_ctl = op->break_ctl; + driver->flush_buffer = op->flush_buffer; + driver->set_ldisc = op->set_ldisc; + driver->wait_until_sent = op->wait_until_sent; + driver->send_xchar = op->send_xchar; + driver->read_proc = op->read_proc; + driver->write_proc = op->write_proc; + driver->tiocmget = op->tiocmget; + driver->tiocmset = op->tiocmset; +} + + +EXPORT_SYMBOL(alloc_tty_driver); +EXPORT_SYMBOL(put_tty_driver); +EXPORT_SYMBOL(tty_set_operations); + +/* + * Called by a tty driver to register itself. + */ +int tty_register_driver(struct tty_driver *driver) +{ + int error; + int i; + dev_t dev; + void **p = NULL; + + if (driver->flags & TTY_DRIVER_INSTALLED) + return 0; + + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); + if (!p) + return -ENOMEM; + memset(p, 0, driver->num * 3 * sizeof(void *)); + } + + if (!driver->major) { + error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, + (char*)driver->name); + if (!error) { + driver->major = MAJOR(dev); + driver->minor_start = MINOR(dev); + } + } else { + dev = MKDEV(driver->major, driver->minor_start); + error = register_chrdev_region(dev, driver->num, + (char*)driver->name); + } + if (error < 0) { + kfree(p); + return error; + } + + if (p) { + driver->ttys = (struct tty_struct **)p; + driver->termios = (struct termios **)(p + driver->num); + driver->termios_locked = (struct termios **)(p + driver->num * 2); + } else { + driver->ttys = NULL; + driver->termios = NULL; + driver->termios_locked = NULL; + } + + cdev_init(&driver->cdev, &tty_fops); + driver->cdev.owner = driver->owner; + error = cdev_add(&driver->cdev, dev, driver->num); + if (error) { + cdev_del(&driver->cdev); + unregister_chrdev_region(dev, driver->num); + driver->ttys = NULL; + driver->termios = driver->termios_locked = NULL; + kfree(p); + return error; + } + + if (!driver->put_char) + driver->put_char = tty_default_put_char; + + list_add(&driver->tty_drivers, &tty_drivers); + + if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) { + for(i = 0; i < driver->num; i++) + tty_register_device(driver, i, NULL); + } + proc_tty_register_driver(driver); + return 0; +} + +EXPORT_SYMBOL(tty_register_driver); + +/* + * Called by a tty driver to unregister itself. + */ +int tty_unregister_driver(struct tty_driver *driver) +{ + int i; + struct termios *tp; + void *p; + + if (driver->refcount) + return -EBUSY; + + unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), + driver->num); + + list_del(&driver->tty_drivers); + + /* + * Free the termios and termios_locked structures because + * we don't want to get memory leaks when modular tty + * drivers are removed from the kernel. + */ + for (i = 0; i < driver->num; i++) { + tp = driver->termios[i]; + if (tp) { + driver->termios[i] = NULL; + kfree(tp); + } + tp = driver->termios_locked[i]; + if (tp) { + driver->termios_locked[i] = NULL; + kfree(tp); + } + if (!(driver->flags & TTY_DRIVER_NO_DEVFS)) + tty_unregister_device(driver, i); + } + p = driver->ttys; + proc_tty_unregister_driver(driver); + driver->ttys = NULL; + driver->termios = driver->termios_locked = NULL; + kfree(p); + cdev_del(&driver->cdev); + return 0; +} + +EXPORT_SYMBOL(tty_unregister_driver); + + +/* + * Initialize the console device. This is called *early*, so + * we can't necessarily depend on lots of kernel help here. + * Just do some early initializations, and do the complex setup + * later. + */ +void __init console_init(void) +{ + initcall_t *call; + + /* Setup the default TTY line discipline. */ + (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); + + /* + * set up the console device so that later boot sequences can + * inform about problems etc.. + */ +#ifdef CONFIG_EARLY_PRINTK + disable_early_printk(); +#endif + call = __con_initcall_start; + while (call < __con_initcall_end) { + (*call)(); + call++; + } +} + +#ifdef CONFIG_VT +extern int vty_init(void); +#endif + +static int __init tty_class_init(void) +{ + tty_class = class_create(THIS_MODULE, "tty"); + if (IS_ERR(tty_class)) + return PTR_ERR(tty_class); + return 0; +} + +postcore_initcall(tty_class_init); + +/* 3/2004 jmc: why do these devices exist? */ + +static struct cdev tty_cdev, console_cdev; +#ifdef CONFIG_UNIX98_PTYS +static struct cdev ptmx_cdev; +#endif +#ifdef CONFIG_VT +static struct cdev vc0_cdev; +#endif + +/* + * Ok, now we can initialize the rest of the tty devices and can count + * on memory allocations, interrupts etc.. + */ +static int __init tty_init(void) +{ + cdev_init(&tty_cdev, &tty_fops); + if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) + panic("Couldn't register /dev/tty driver\n"); + devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + + cdev_init(&console_cdev, &console_fops); + if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) + panic("Couldn't register /dev/console driver\n"); + devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + +#ifdef CONFIG_UNIX98_PTYS + cdev_init(&ptmx_cdev, &ptmx_fops); + if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) + panic("Couldn't register /dev/ptmx driver\n"); + devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); + class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); +#endif + +#ifdef CONFIG_VT + if (!console_use_vt) + goto out_vt; + cdev_init(&vc0_cdev, &console_fops); + if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || + register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) + panic("Couldn't register /dev/tty0 driver\n"); + devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); + class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + + vty_init(); + out_vt: +#endif + return 0; +} +module_init(tty_init); diff --git a/linux-2.6-xen-sparse/drivers/xen/console/console.c b/linux-2.6-xen-sparse/drivers/xen/console/console.c index f184f6ac35..3b48932e0a 100644 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c @@ -66,14 +66,14 @@ * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'. * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'. * 'xencons=xvc' [XC_XVC]: Console attached to '/dev/xvc0'. - * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY. + * default: DOM0 -> XC_SERIAL ; all others -> XC_TTY. * * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses * warnings from standard distro startup scripts. */ static enum { - XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC -} xc_mode = XC_DEFAULT; + XC_OFF, XC_TTY, XC_SERIAL, XC_XVC +} xc_mode; static int xc_num = -1; /* /dev/xvc0 device number allocated by lanana.org. */ @@ -85,17 +85,32 @@ static unsigned long sysrq_requested; extern int sysrq_enabled; #endif +void xencons_early_setup(void) +{ + extern int console_use_vt; + + if (is_initial_xendomain()) { + xc_mode = XC_SERIAL; + } else { + xc_mode = XC_TTY; + console_use_vt = 0; + } +} + static int __init xencons_setup(char *str) { char *q; int n; + extern int console_use_vt; + console_use_vt = 1; if (!strncmp(str, "ttyS", 4)) { xc_mode = XC_SERIAL; str += 4; } else if (!strncmp(str, "tty", 3)) { xc_mode = XC_TTY; str += 3; + console_use_vt = 0; } else if (!strncmp(str, "xvc", 3)) { xc_mode = XC_XVC; str += 3; @@ -193,14 +208,10 @@ static int __init xen_console_init(void) goto out; if (is_initial_xendomain()) { - if (xc_mode == XC_DEFAULT) - xc_mode = XC_SERIAL; kcons_info.write = kcons_write_dom0; } else { if (!xen_start_info->console.domU.evtchn) goto out; - if (xc_mode == XC_DEFAULT) - xc_mode = XC_TTY; kcons_info.write = kcons_write; } @@ -699,15 +710,6 @@ static int __init xencons_init(void) printk("Xen virtual console successfully installed as %s%d\n", DRV(xencons_driver)->name, xc_num); - /* Check about framebuffer messing up the console */ - if (!is_initial_xendomain() && - !xenbus_exists(XBT_NIL, "device", "vfb")) { - /* FIXME: this is ugly */ - unregister_console(&kcons_info); - kcons_info.flags |= CON_CONSDEV; - register_console(&kcons_info); - } - return 0; } diff --git a/linux-2.6-xen-sparse/include/xen/xencons.h b/linux-2.6-xen-sparse/include/xen/xencons.h index ae873746aa..9f280c5e0b 100644 --- a/linux-2.6-xen-sparse/include/xen/xencons.h +++ b/linux-2.6-xen-sparse/include/xen/xencons.h @@ -14,4 +14,6 @@ void xencons_tx(void); int xencons_ring_init(void); int xencons_ring_send(const char *data, unsigned len); +void xencons_early_setup(void); + #endif /* __ASM_XENCONS_H__ */ From 43bcc64d9992847e69c9b65c290d5bf6d01f1753 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 11:54:53 +0000 Subject: [PATCH 127/282] [XEN] Quieten down HVM debug output. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vlapic.c | 2 +- xen/arch/x86/x86_emulate.c | 40 +++++++++++--------------------------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 60e6171c47..a0304deb37 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -723,7 +723,7 @@ static void vlapic_write(struct vcpu *v, unsigned long address, break; default: - gdprintk(XENLOG_WARNING, + gdprintk(XENLOG_DEBUG, "Local APIC Write to read-only register 0x%x\n", offset); break; } diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 555655f83a..e5f6a6b503 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -7,16 +7,14 @@ */ #ifndef __XEN__ -#include +#include #include #include -#define dprintf(_f, _a...) printf( _f , ## _a ) #else #include #include #include #include -#define dprintf(_f, _a...) gdprintk(XENLOG_WARNING, _f , ## _a ) #undef cmpxchg #endif #include @@ -440,27 +438,6 @@ decode_register( return p; } -static void -dump_instr( - struct x86_emulate_ctxt *ctxt, - struct x86_emulate_ops *ops) -{ -#ifdef __XEN__ - int i; - unsigned long x, eip = ctxt->regs->eip; - - dprintf("Instr:"); - for ( i = 0; i < 16; i++, eip++ ) - { - if ( ops->read(x86_seg_cs, eip, &x, 1, ctxt) != 0 ) - printk(" ??"); - else - printk(" %02x", (uint8_t)x); - } - printk("\n"); -#endif -} - int x86_emulate_memop( struct x86_emulate_ctxt *ctxt, @@ -579,10 +556,7 @@ x86_emulate_memop( modrm_rm = modrm & 0x07; if ( modrm_mod == 3 ) - { - dprintf("Cannot parse ModRM.mod == 3.\n"); goto cannot_emulate; - } if ( ad_bytes == 2 ) { @@ -1206,7 +1180,15 @@ x86_emulate_memop( goto writeback; cannot_emulate: - dprintf("Cannot emulate %02x\n", b); - dump_instr(ctxt, ops); +#ifdef __XEN__ + gdprintk(XENLOG_DEBUG, "Instr:"); + for ( ea_off = ctxt->regs->eip; ea_off < _regs.eip; ea_off++ ) + { + unsigned long x; + ops->read(x86_seg_cs, ea_off, &x, 1, ctxt); + printk(" %02x", (uint8_t)x); + } + printk("\n"); +#endif return -1; } From 14dc44913037f6e2ba9a2871addd3d4a49498797 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 12:03:15 +0000 Subject: [PATCH 128/282] [PVFB] Make sure that framebuffer backend goes away when the domain terminates, and that it cleans up its area of xenstore. Tidy up argument parsing a little while I'm here. Signed-off-by: Steven Smith --- tools/xenfb/sdlfb.c | 10 +++++++++- tools/xenfb/vncfb.c | 10 +++++++++- tools/xenfb/xenfb.c | 27 ++++++++++++++++++++++++--- tools/xenfb/xenfb.h | 1 + 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/tools/xenfb/sdlfb.c b/tools/xenfb/sdlfb.c index cc5f8d6f52..6276c34659 100644 --- a/tools/xenfb/sdlfb.c +++ b/tools/xenfb/sdlfb.c @@ -204,6 +204,7 @@ static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event) static struct option options[] = { { "domid", 1, NULL, 'd' }, { "title", 1, NULL, 't' }, + { NULL } }; int main(int argc, char **argv) @@ -220,6 +221,7 @@ int main(int argc, char **argv) int do_quit = 0; int opt; char *endp; + int retval; while ((opt = getopt_long(argc, argv, "d:t:", options, NULL)) != -1) { @@ -234,6 +236,8 @@ int main(int argc, char **argv) case 't': title = strdup(optarg); break; + case '?': + exit(1); } } if (optind != argc) { @@ -323,7 +327,11 @@ int main(int argc, char **argv) if (do_quit) break; - xenfb_poll(xenfb, &readfds); + retval = xenfb_poll(xenfb, &readfds); + if (retval == -2) + xenfb_teardown(xenfb); + if (retval < 0) + break; } xenfb_delete(xenfb); diff --git a/tools/xenfb/vncfb.c b/tools/xenfb/vncfb.c index 2fc970e0cc..49fc730625 100644 --- a/tools/xenfb/vncfb.c +++ b/tools/xenfb/vncfb.c @@ -253,6 +253,7 @@ static struct option options[] = { { "title", 1, NULL, 't' }, { "unused", 0, NULL, 'u' }, { "listen", 1, NULL, 'l' }, + { NULL } }; int main(int argc, char **argv) @@ -272,6 +273,7 @@ int main(int argc, char **argv) int nfds; char portstr[10]; char *endp; + int r; while ((opt = getopt_long(argc, argv, "d:p:t:u", options, NULL)) != -1) { @@ -301,6 +303,8 @@ int main(int argc, char **argv) case 'l': listen = strdup(optarg); break; + case '?': + exit(1); } } if (optind != argc) { @@ -383,7 +387,11 @@ int main(int argc, char **argv) break; } - xenfb_poll(xenfb, &readfds); + r = xenfb_poll(xenfb, &readfds); + if (r == -2) + xenfb_teardown(xenfb); + if (r < 0) + break; } rfbScreenCleanup(server); diff --git a/tools/xenfb/xenfb.c b/tools/xenfb/xenfb.c index 82d31772df..496a365079 100644 --- a/tools/xenfb/xenfb.c +++ b/tools/xenfb/xenfb.c @@ -187,6 +187,17 @@ struct xenfb *xenfb_new(void) return NULL; } +/* Remove the backend area in xenbus since the framebuffer really is + going away. */ +void xenfb_teardown(struct xenfb *xenfb_pub) +{ + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; + + xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename); + xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename); +} + + void xenfb_delete(struct xenfb *xenfb_pub) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; @@ -564,7 +575,7 @@ static void xenfb_on_kbd_event(struct xenfb_private *xenfb) xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port); } -static void xenfb_on_state_change(struct xenfb_device *dev) +static int xenfb_on_state_change(struct xenfb_device *dev) { enum xenbus_state state; @@ -572,6 +583,10 @@ static void xenfb_on_state_change(struct xenfb_device *dev) switch (state) { case XenbusStateUnknown: + /* There was an error reading the frontend state. The + domain has probably gone away; in any case, there's + not much point in us continuing. */ + return -1; case XenbusStateInitialising: case XenbusStateInitWait: case XenbusStateInitialised: @@ -585,14 +600,17 @@ static void xenfb_on_state_change(struct xenfb_device *dev) xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); xenfb_switch_state(dev, state); } + return 0; } +/* Returns 0 normally, -1 on error, or -2 if the domain went away. */ int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) { struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; evtchn_port_t port; unsigned dummy; char **vec; + int r; if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) { port = xc_evtchn_pending(xenfb->evt_xch); @@ -611,8 +629,11 @@ int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds) if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) { vec = xs_read_watch(xenfb->xsh, &dummy); free(vec); - xenfb_on_state_change(&xenfb->fb); - xenfb_on_state_change(&xenfb->kbd); + r = xenfb_on_state_change(&xenfb->fb); + if (r == 0) + r = xenfb_on_state_change(&xenfb->kbd); + if (r == -1) + return -2; } return 0; diff --git a/tools/xenfb/xenfb.h b/tools/xenfb/xenfb.h index 007eb3b9b4..c08d979b39 100644 --- a/tools/xenfb/xenfb.h +++ b/tools/xenfb/xenfb.h @@ -21,6 +21,7 @@ struct xenfb struct xenfb *xenfb_new(void); void xenfb_delete(struct xenfb *xenfb); +void xenfb_teardown(struct xenfb *xenfb); int xenfb_attach_dom(struct xenfb *xenfb, int domid); From f44748c2b6ebedb7f9de9e62711b4f23580e89d6 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 12:09:10 +0000 Subject: [PATCH 129/282] [TOOLS] Remove some dead code. Signed-off-by: Steven Smith --- tools/python/xen/xend/image.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index aeff0f0702..8d2aab1836 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -199,13 +199,6 @@ class LinuxImageHandler(ImageHandler): ramdisk = self.ramdisk, features = self.vm.getFeatures()) - def destroy(self): - if not self.pid: - return - os.kill(self.pid, signal.SIGKILL) - os.waitpid(self.pid, 0) - self.pid = 0 - class PPC_LinuxImageHandler(LinuxImageHandler): ostype = "linux" From 4ae8d4056ed408362007acf8550f62cec4b563ae Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 12:20:12 +0000 Subject: [PATCH 130/282] [TOOLS][PVFB] Avoid zombie framebuffer backends. Signed-off-by: Steven Smith --- tools/python/xen/xend/server/vfbif.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/server/vfbif.py b/tools/python/xen/xend/server/vfbif.py index 4540031633..d4a28542f1 100644 --- a/tools/python/xen/xend/server/vfbif.py +++ b/tools/python/xen/xend/server/vfbif.py @@ -4,6 +4,14 @@ from xen.xend.XendError import VmError import xen.xend import os +def spawn_detached(path, args, env): + p = os.fork() + if p == 0: + os.spawnve(os.P_NOWAIT, path, args, env) + os._exit(0) + else: + os.waitpid(p, 0) + class VfbifController(DevController): """Virtual frame buffer controller. Handles all vfb devices for a domain. """ @@ -33,7 +41,7 @@ class VfbifController(DevController): vnclisten = config.get("vnclisten", xen.xend.XendRoot.instance().get_vnclisten_address()) args += [ "--listen", vnclisten ] - os.spawnve(os.P_NOWAIT, args[0], args + std_args, os.environ) + spawn_detached(args[0], args + std_args, os.environ) elif t == "sdl": args = [xen.util.auxbin.pathTo("xen-sdlfb")] env = dict(os.environ) @@ -41,7 +49,7 @@ class VfbifController(DevController): env['DISPLAY'] = config["display"] if config.has_key("xauthority"): env['XAUTHORITY'] = config["xauthority"] - os.spawnve(os.P_NOWAIT, args[0], args + std_args, env) + spawn_detached(args[0], args + std_args, env) else: raise VmError('Unknown vfb type %s (%s)' % (t, repr(config))) From 91e35907b2e5c296b1d215a3630d470629f3be3c Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 12:24:42 +0000 Subject: [PATCH 131/282] Link test/test_bindings against libxenapi in the new location. Signed-off-by: Ewan Mellor --- tools/libxen/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/libxen/Makefile b/tools/libxen/Makefile index 6bf5d2fc25..c72206442a 100644 --- a/tools/libxen/Makefile +++ b/tools/libxen/Makefile @@ -48,8 +48,8 @@ libxenapi.so.$(MAJOR).$(MINOR): $(LIBXENAPI_OBJS) libxenapi.a: $(LIBXENAPI_OBJS) $(AR) rcs libxenapi.a $^ -test/test_bindings: test/test_bindings.o src/libxen.so - $(CC) $(LDFLAGS) -o $@ $< -L src -lxen +test/test_bindings: test/test_bindings.o libxenapi.so + $(CC) $(LDFLAGS) -o $@ $< -L . -lxenapi .PHONY: install From e9167464c49a7e0e7b2a13f0efeb4942c93da3ea Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 12:38:41 +0000 Subject: [PATCH 132/282] [PVFB][TOOLS] Fix save/restore for domains with PV framebuffers. Signed-off-by: Steven Smith --- tools/python/xen/xend/server/vfbif.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/server/vfbif.py b/tools/python/xen/xend/server/vfbif.py index d4a28542f1..e24c2284f6 100644 --- a/tools/python/xen/xend/server/vfbif.py +++ b/tools/python/xen/xend/server/vfbif.py @@ -14,11 +14,13 @@ def spawn_detached(path, args, env): class VfbifController(DevController): """Virtual frame buffer controller. Handles all vfb devices for a domain. + Note that we only support a single vfb per domain at the moment. """ def __init__(self, vm): DevController.__init__(self, vm) - + self.config = {} + def getDeviceDetails(self, config): """@see DevController.getDeviceDetails""" devid = 0 @@ -26,8 +28,15 @@ class VfbifController(DevController): front = {} return (devid, back, front) + def getDeviceConfiguration(self, devid): + r = DevController.getDeviceConfiguration(self, devid) + for (k,v) in self.config.iteritems(): + r[k] = v + return r + def createDevice(self, config): DevController.createDevice(self, config) + self.config = config std_args = [ "--domid", "%d" % self.vm.getDomid(), "--title", self.vm.getName() ] t = config.get("type", None) From c7a44ef04b6d3e68c5852e81643214199c47437a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 13:06:15 +0000 Subject: [PATCH 133/282] Include the rotated xend.log.X in the bug report. Signed-off-by: Ewan Mellor --- tools/python/xen/util/bugtool.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/util/bugtool.py b/tools/python/xen/util/bugtool.py index 77df9d4420..18569dcb33 100644 --- a/tools/python/xen/util/bugtool.py +++ b/tools/python/xen/util/bugtool.py @@ -43,8 +43,9 @@ TITLE_RE = re.compile(r'(.*)') FILES_TO_SEND = [ '/var/log/' + x for x in [ 'syslog', 'messages', 'debug', - 'xen/xend.log', 'xen/xend-debug.log', 'xen/xenstored-trace.log', - 'xen/xen-hotplug.log' ] ] + 'xen/xend-debug.log', 'xen/xenstored-trace.log', + 'xen/xen-hotplug.log', 'xen/xend.log' ] + + [ 'xen/xend.log.%d' % z for z in range(1,6) ] ] #FILES_TO_SEND = [ ] From 2f61385eede3f8651d97664a5e6a3e28649de84d Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 13:07:19 +0000 Subject: [PATCH 134/282] Added log message for when a VM is deleted. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomain.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index bb14e70667..5ebb7e6240 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -929,6 +929,9 @@ class XendDomain: if dominfo.state != DOM_STATE_HALTED: raise XendError("Domain is still running") + log.info("Domain %s (%s) deleted." % + (dominfo.getName(), dominfo.info.get('uuid'))) + self._managed_domain_unregister(dominfo) self._remove_domain(dominfo) XendDevices.destroy_device_state(dominfo) From 7be5d5173c9e7065f37fd430876490911ff448e7 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 13:08:36 +0000 Subject: [PATCH 135/282] Set localtime, enable_audio, clock_offset, and std_vga back to being bools, not ints. This is a recent breakage. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index d606dbb7bb..e528170a95 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -57,6 +57,11 @@ xroot = XendRoot.instance() log = logging.getLogger("xend.XendDomainInfo") #log.setLevel(logging.TRACE) + +def bool0(v): + v != "0" and bool(v) + + ## # All parameters of VMs that may be configured on-the-fly, or at start-up. # @@ -87,7 +92,7 @@ ROUNDTRIPPING_CONFIG_ENTRIES = [ ('bootloader', str), ('bootloader_args', str), ('features', str), - ('localtime', int), + ('localtime', bool0), ] ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_PARAMS @@ -1323,8 +1328,8 @@ class XendDomainInfo: self.info['image'], self.info['devices']) - localtime = self.info.get('localtime', 0) - if localtime is not None and localtime == 1: + localtime = self.info.get('localtime', False) + if localtime: xc.domain_set_time_offset(self.domid) xc.domain_setcpuweight(self.domid, self.info['cpu_weight']) @@ -1780,17 +1785,17 @@ class XendDomainInfo: def get_bios_boot(self): return '' # TODO def get_platform_std_vga(self): - return self.info.get('platform_std_vga', 0) + return self.info.get('platform_std_vga', False) def get_platform_keymap(self): return '' def get_platform_serial(self): return self.info.get('platform_serial', '') def get_platform_localtime(self): - return self.info.get('platform_localtime', 0) + return self.info.get('platform_localtime', False) def get_platform_clock_offset(self): - return self.info.get('platform_clock_offset', 0) + return self.info.get('platform_clock_offset', False) def get_platform_enable_audio(self): - return self.info.get('platform_enable_audio', 0) + return self.info.get('platform_enable_audio', False) def get_platform_keymap(self): return self.info.get('platform_keymap', '') def get_builder(self): From 4ffdeb2ddc7270a935ed838daa72fc77ec18c3d1 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Fri, 1 Dec 2006 13:11:53 +0000 Subject: [PATCH 136/282] [PVFB][TOOLS] Don't unwatch the framebuffer frontend's state node just because it want to state Closed. Otherwise, we don't notice when the node gets deleted, and can't reliably shut the backend down. Signed-off-by: Steven Smith --- tools/xenfb/xenfb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/xenfb/xenfb.c b/tools/xenfb/xenfb.c index 496a365079..19ab6c9553 100644 --- a/tools/xenfb/xenfb.c +++ b/tools/xenfb/xenfb.c @@ -597,7 +597,6 @@ static int xenfb_on_state_change(struct xenfb_device *dev) xenfb_switch_state(dev, state); break; case XenbusStateClosed: - xs_unwatch(dev->xenfb->xsh, dev->otherend, ""); xenfb_switch_state(dev, state); } return 0; From 4dc8c41b11aa24edcf04b0c2f1248fa4ad58d40b Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 13:09:30 +0000 Subject: [PATCH 137/282] Update README to reflect moved library. Signed-off-by: Ewan Mellor --- tools/libxen/README | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/libxen/README b/tools/libxen/README index 4aa9450381..2dd79f46fc 100644 --- a/tools/libxen/README +++ b/tools/libxen/README @@ -44,11 +44,12 @@ The bindings depend upon libxml2, the XML toolkit from the GNOME project; the test program depends upon libcurl3 also. On Debian, you need the packages libxml2-dev and libcurl3-dev. -To compile, type make. +To compile, type make. To compile the test also, type make +test/test_bindings, remembering the additional dependency. To run the test, do -LD_LIBRARY_PATH=src ./test/test_bindings +LD_LIBRARY_PATH=. ./test/test_bindings where is the fragment of the server URL that follows the http://, for example "localhost:8005/RPC2". From 4bdbd7644a6fac7fac31599205306496b28e0062 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 13:25:33 +0000 Subject: [PATCH 138/282] Actually return something from bool0. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index e528170a95..dd8c2c3b27 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -59,7 +59,7 @@ log = logging.getLogger("xend.XendDomainInfo") def bool0(v): - v != "0" and bool(v) + return v != "0" and bool(v) ## From 65ade46c57d850062d246470a3552bb026a8f602 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 13:44:33 +0000 Subject: [PATCH 139/282] [LINUX] dev/mem: Rename Xen's mmap_mem to xen_mmap_mem to avoid conflict with the definition (which still exists and is used) in drivers/char/mem.c. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/char/mem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/char/mem.c b/linux-2.6-xen-sparse/drivers/xen/char/mem.c index ac85c8dbb2..135bad413e 100644 --- a/linux-2.6-xen-sparse/drivers/xen/char/mem.c +++ b/linux-2.6-xen-sparse/drivers/xen/char/mem.c @@ -147,7 +147,7 @@ static inline int uncached_access(struct file *file) return 0; } -static int mmap_mem(struct file * file, struct vm_area_struct * vma) +static int xen_mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; @@ -200,6 +200,6 @@ struct file_operations mem_fops = { .llseek = memory_lseek, .read = read_mem, .write = write_mem, - .mmap = mmap_mem, + .mmap = xen_mmap_mem, .open = open_mem, }; From 2e23acca5528f66bd258c2e32a6741786c74af79 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 13:53:04 +0000 Subject: [PATCH 140/282] [XEND] Ensure config value types in XendConfig Add definitions of what we expect the types to be for the values in XendConfig and apply them when parsing SXP where all values are either strings or list. Also fix missing stdvga in HVM config. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 120 ++++++++++++++++------------ 1 file changed, 68 insertions(+), 52 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 846aebda02..8cec14ba0e 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -39,6 +39,9 @@ def reverse_dict(adict): """Return the reverse mapping of a dictionary.""" return dict([(v, k) for k, v in adict.items()]) +def bool0(v): + return v != '0' and bool(v) + # Mapping from XendConfig configuration keys to the old # legacy configuration keys that map directly. @@ -60,7 +63,7 @@ LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG) # legacy configuration keys that are found in the 'image' # SXP object. XENAPI_HVM_CFG = { - 'platform_std_vga': 'std-vga', + 'platform_std_vga': 'stdvga', 'platform_serial' : 'serial', 'platform_localtime': 'localtime', 'platform_enable_audio': 'soundhw', @@ -70,33 +73,49 @@ XENAPI_HVM_CFG = { # List of XendConfig configuration keys that have no equivalent # in the old world. -XENAPI_UNSUPPORTED_BY_LEGACY_CFG = [ - 'name_description', - 'user_version', - 'is_a_template', - 'memory_dynamic_min', - 'memory_dynamic_max', - 'memory_actual', - 'vcpus_policy', - 'vcpus_params', - 'vcpus_features_required', - 'vcpus_features_can_use', - 'vcpus_features_force_on', - 'vcpus_features_force_off', - 'actions_after_suspend', - 'bios_boot', - 'platform_std_vga', - 'platform_serial', - 'platform_localtime', - 'platform_clock_offset', - 'platform_enable_audio', - 'platform_keymap', - 'boot_method', - 'builder', - 'grub_cmdline', - 'pci_bus', - 'otherconfig' -] +XENAPI_CFG_TYPES = { + 'uuid': str, + 'power_state': int, + 'name_label': str, + 'name_description': str, + 'user_version': str, + 'is_a_template': int, + 'resident_on': str, + 'memory_static_min': int, + 'memory_static_max': int, + 'memory_dynamic_min': int, + 'memory_dynamic_max': int, + 'memory_actual': int, + 'vcpus_policy': str, + 'vcpus_params': str, + 'vcpus_number': int, + 'vcpus_features_required': list, + 'vcpus_features_can_use': list, + 'vcpus_features_force_on': list, + 'vcpus_features_force_off': list, + 'actions_after_shutdown': str, + 'actions_after_reboot': str, + 'actions_after_suspend': str, + 'actions_after_crash': str, + 'tpm_instance': int, + 'tpm_backend': int, + 'bios_boot': str, + 'platform_std_vga': bool0, + 'platform_serial': str, + 'platform_localtime': bool0, + 'platform_clock_offset': bool0, + 'platform_enable_audio': bool0, + 'platform_keymap': str, + 'boot_method': int, + 'builder': str, + 'kernel_kernel': str, + 'kernel_initrd': str, + 'kernel_args': str, + 'grub_cmdline': str, + 'pci_bus': str, + 'tools_version': dict, + 'otherconfig': dict, +} # List of legacy configuration keys that have no equivalent in the # Xen API, but are still stored in XendConfig. @@ -146,6 +165,7 @@ LEGACY_CFG_TYPES = { 'on_crash': str, 'on_xend_stop': str, 'on_xend_start': str, + 'online_vcpus': int, } # Values that should be stored in xenstore's /vm/ that is used @@ -203,23 +223,6 @@ LEGACY_IMAGE_HVM_DEVICES_CFG = [ ('vcpus', int), ] - - -# configuration params that need to be converted to ints -# since the XMLRPC transport for Xen API does not use -# 32 bit ints but string representation of 64 bit ints. -XENAPI_INT_CFG = [ - 'user_version', - 'vcpus_number', - 'memory_static_min', - 'memory_static_max', - 'memory_dynamic_min', - 'memory_dynamic_max', - 'memory_actual', - 'tpm_instance', - 'tpm_backend', -] - ## ## Config Choices ## @@ -532,7 +535,12 @@ class XendConfig(dict): for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items(): try: - self[apikey] = LEGACY_CFG_TYPES[cfgkey](cfg[cfgkey]) + type_conv = XENAPI_CFG_TYPES.get(apikey) + if callable(type_conv): + self[apikey] = type_conv(cfg[cfgkey]) + else: + log.warn("Unconverted key: " + apikey) + self[apikey] = cfg[cfgkey] except KeyError: pass @@ -555,10 +563,10 @@ class XendConfig(dict): self['kernel_args'] = kernel_args # Convert Legacy HVM parameters to Xen API configuration - self['platform_std_vga'] = cfg.get('std-vga', 0) - self['platform_serial'] = cfg.get('serial', '') - self['platform_localtime'] = cfg.get('localtime', 0) - self['platform_enable_audio'] = cfg.get('soundhw', 0) + self['platform_std_vga'] = bool0(cfg.get('stdvga', 0)) + self['platform_serial'] = str(cfg.get('serial', '')) + self['platform_localtime'] = bool0(cfg.get('localtime', 0)) + self['platform_enable_audio'] = bool0(cfg.get('soundhw', 0)) # Convert path to bootloader to boot_method if not cfg.get('bootloader'): @@ -733,7 +741,11 @@ class XendConfig(dict): for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items(): if self.has_key(xenapi) and self[xenapi] not in (None, []): - sxpr.append([legacy, self[xenapi]]) + if type(self[xenapi]) == bool: + # convert booleans to ints before making an sxp item + sxpr.append([legacy, int(self[xenapi])]) + else: + sxpr.append([legacy, self[xenapi]]) for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG: if legacy in ('domid', 'uuid'): # skip these @@ -1043,7 +1055,11 @@ class XendConfig(dict): for apikey, imgkey in XENAPI_HVM_CFG.items(): val = sxp.child_value(image_sxp, imgkey, None) if val != None: - self[apikey] = val + type_conv = XENAPI_CFG_TYPES[apikey] + if callable(conv): + self[apikey] = type_conv(val) + else: + self[apikey] = val # From ea1248436a8ebe048ac70c5967a6904d4c78073d Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 13:55:28 +0000 Subject: [PATCH 141/282] [XEND] Reapply fix for ever expanding kernel_args in XendConfig Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 8cec14ba0e..375ba473a4 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -554,7 +554,7 @@ class XendConfig(dict): # attempt to extract extra arguments from SXP config arg_ip = sxp.child_value(image_sxp, 'ip') - if arg_ip and not re.search(r'ip=[0-9\.]+', kernel_args): + if arg_ip and not re.search(r'ip=[^ ]+', kernel_args): kernel_args += ' ip=%s' % arg_ip arg_root = sxp.child_value(image_sxp, 'root') if arg_root and not re.search(r'root=[^ ]+', kernel_args): @@ -1019,7 +1019,7 @@ class XendConfig(dict): # attempt to extract extra arguments from SXP config arg_ip = sxp.child_value(image_sxp, 'ip') - if arg_ip and not re.search(r'ip=[0-9\.]', kernel_args): + if arg_ip and not re.search(r'ip=[^ ]+', kernel_args): kernel_args += ' ip=%s' % arg_ip arg_root = sxp.child_value(image_sxp, 'root') if arg_root and not re.search(r'root=', kernel_args): From 2aba25fee2273946a15c8766cb252808c6f60f99 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 13:57:46 +0000 Subject: [PATCH 142/282] [XEN] Emulate XADD instruction. Signed-off-by: Keir Fraser --- tools/tests/test_x86_emulator.c | 20 ++++++++++++++++++++ xen/arch/x86/x86_emulate.c | 17 +++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c index 31f1abcb02..e22e342ce2 100644 --- a/tools/tests/test_x86_emulator.c +++ b/tools/tests/test_x86_emulator.c @@ -304,6 +304,7 @@ int main(int argc, char **argv) printf("%-40s", "Testing cmpxchg8b (%edi) [failing]..."); instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f; + regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.edi = (unsigned long)res; regs.error_code = PFEC_write_access; @@ -320,6 +321,7 @@ int main(int argc, char **argv) printf("%-40s", "Testing movsxbd (%%eax),%%ecx..."); instr[0] = 0x0f; instr[1] = 0xbe; instr[2] = 0x08; + regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.ecx = 0x12345678; regs.eax = (unsigned long)res; @@ -336,6 +338,7 @@ int main(int argc, char **argv) printf("%-40s", "Testing movzxwd (%%eax),%%ecx..."); instr[0] = 0x0f; instr[1] = 0xb7; instr[2] = 0x08; + regs.eflags = 0x200; regs.eip = (unsigned long)&instr[0]; regs.ecx = 0x12345678; regs.eax = (unsigned long)res; @@ -350,6 +353,23 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); + printf("%-40s", "Testing xadd %%ax,(%%ecx)..."); + instr[0] = 0x66; instr[1] = 0x0f; instr[2] = 0xc1; instr[3] = 0x01; + regs.eflags = 0x200; + regs.eip = (unsigned long)&instr[0]; + regs.ecx = (unsigned long)res; + regs.eax = 0x12345678; + *res = 0x11111111; + regs.error_code = 0; + rc = x86_emulate_memop(&ctxt, &emulops); + if ( (rc != 0) || + (*res != 0x11116789) || + (regs.eax != 0x12341111) || + ((regs.eflags&0x240) != 0x200) || + (regs.eip != (unsigned long)&instr[4]) ) + goto fail; + printf("okay\n"); + return 0; fail: diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index e5f6a6b503..1582bdf299 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -179,8 +179,11 @@ static uint8_t twobyte_table[256] = { /* 0xB8 - 0xBF */ 0, 0, DstBitBase|SrcImmByte|ModRM, DstBitBase|SrcReg|ModRM, 0, 0, ByteOp|DstReg|SrcMem|ModRM|Mov, DstReg|SrcMem16|ModRM|Mov, - /* 0xC0 - 0xCF */ - 0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0, + /* 0xC0 - 0xC7 */ + ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, 0, + 0, 0, 0, ImplicitOps|ModRM, + /* 0xC8 - 0xCF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0xD0 - 0xDF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0 - 0xEF */ @@ -1116,6 +1119,16 @@ x86_emulate_memop( dst.bytes = op_bytes; dst.val = (d & ByteOp) ? (int8_t)src.val : (int16_t)src.val; break; + case 0xc0 ... 0xc1: /* xadd */ + /* Write back the register source. */ + switch ( dst.bytes ) + { + case 1: *(uint8_t *)src.reg = (uint8_t)dst.val; break; + case 2: *(uint16_t *)src.reg = (uint16_t)dst.val; break; + case 4: *src.reg = (uint32_t)dst.val; break; /* 64b reg: zero-extend */ + case 8: *src.reg = dst.val; break; + } + goto add; } goto writeback; From fcad36eb8028ea9f480d0361dc2cd2efe7fbe668 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 14:25:36 +0000 Subject: [PATCH 143/282] [LIBXC] Add new AP{I function xc_evtchn_bind_unbound_port(). Add a comment clarifying how this function differs from xc_evtchn_alloc_unbound(). Signed-off-by: Keir Fraser --- tools/libxc/xc_linux.c | 9 +++++++++ tools/libxc/xc_solaris.c | 9 +++++++++ tools/libxc/xenctrl.h | 16 +++++++++++++--- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/tools/libxc/xc_linux.c b/tools/libxc/xc_linux.c index a70307a542..fa4927aafa 100644 --- a/tools/libxc/xc_linux.c +++ b/tools/libxc/xc_linux.c @@ -250,6 +250,15 @@ int xc_evtchn_notify(int xce_handle, evtchn_port_t port) return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, ¬ify); } +evtchn_port_t xc_evtchn_bind_unbound_port(int xce_handle, int domid) +{ + struct ioctl_evtchn_bind_unbound_port bind; + + bind.remote_domain = domid; + + return ioctl(xce_handle, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind); +} + evtchn_port_t xc_evtchn_bind_interdomain(int xce_handle, int domid, evtchn_port_t remote_port) { diff --git a/tools/libxc/xc_solaris.c b/tools/libxc/xc_solaris.c index 902de64fa4..889db6396d 100644 --- a/tools/libxc/xc_solaris.c +++ b/tools/libxc/xc_solaris.c @@ -165,6 +165,15 @@ int xc_evtchn_notify(int xce_handle, evtchn_port_t port) return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, ¬ify); } +evtchn_port_t xc_evtchn_bind_unbound_port(int xce_handle, int domid) +{ + struct ioctl_evtchn_bind_unbound_port bind; + + bind.remote_domain = domid; + + return ioctl(xce_handle, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind); +} + evtchn_port_t xc_evtchn_bind_interdomain(int xce_handle, int domid, evtchn_port_t remote_port) { diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index c646d18ea8..3904cede84 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -382,6 +382,10 @@ int xc_sched_credit_domain_get(int xc_handle, * This function allocates an unbound port. Ports are named endpoints used for * interdomain communication. This function is most useful in opening a * well-known port within a domain to receive events on. + * + * NOTE: If you are allocating a *local* unbound port, you probably want to + * use xc_evtchn_bind_unbound_port(). This function is intended for allocating + * ports *only* during domain creation. * * @parm xc_handle a handle to an open hypervisor interface * @parm dom the ID of the local domain (the 'allocatee') @@ -629,6 +633,12 @@ int xc_evtchn_fd(int xce_handle); */ int xc_evtchn_notify(int xce_handle, evtchn_port_t port); +/* + * Returns a new event port awaiting interdomain connection from the given + * domain ID, or -1 on failure, in which case errno will be set appropriately. + */ +evtchn_port_t xc_evtchn_bind_unbound_port(int xce_handle, int domid); + /* * Returns a new event port bound to the remote port for the given domain ID, * or -1 on failure, in which case errno will be set appropriately. @@ -661,15 +671,15 @@ evtchn_port_t xc_evtchn_pending(int xce_handle); int xc_evtchn_unmask(int xce_handle, evtchn_port_t port); int xc_hvm_set_pci_intx_level( - int xce_handle, domid_t dom, + int xc_handle, domid_t dom, uint8_t domain, uint8_t bus, uint8_t device, uint8_t intx, unsigned int level); int xc_hvm_set_isa_irq_level( - int xce_handle, domid_t dom, + int xc_handle, domid_t dom, uint8_t isa_irq, unsigned int level); int xc_hvm_set_pci_link_route( - int xce_handle, domid_t dom, uint8_t link, uint8_t isa_irq); + int xc_handle, domid_t dom, uint8_t link, uint8_t isa_irq); #endif From 99d29a0c3f9ab3218f261d5861f978b8d79f5db8 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 14:29:32 +0000 Subject: [PATCH 144/282] [XEN] Remove uses of 'extern inline'. Original patch by Christoph Egger at AMD. Signed-off-by: Keir Fraser --- xen/include/asm-ia64/elf.h | 2 +- xen/include/asm-powerpc/elf.h | 2 +- xen/include/asm-x86/x86_32/elf.h | 2 +- xen/include/asm-x86/x86_64/elf.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/xen/include/asm-ia64/elf.h b/xen/include/asm-ia64/elf.h index fbd92bf4cd..0bdbd9c735 100644 --- a/xen/include/asm-ia64/elf.h +++ b/xen/include/asm-ia64/elf.h @@ -11,7 +11,7 @@ typedef struct { unsigned long dummy; } crash_xen_core_t; -extern inline void elf_core_save_regs(ELF_Gregset *core_regs, +static inline void elf_core_save_regs(ELF_Gregset *core_regs, crash_xen_core_t *xen_core_regs) { printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); diff --git a/xen/include/asm-powerpc/elf.h b/xen/include/asm-powerpc/elf.h index 24fc958387..3877c0f5fa 100644 --- a/xen/include/asm-powerpc/elf.h +++ b/xen/include/asm-powerpc/elf.h @@ -11,7 +11,7 @@ typedef struct { unsigned long dummy; } crash_xen_core_t; -extern inline void elf_core_save_regs(ELF_Gregset *core_regs, +static inline void elf_core_save_regs(ELF_Gregset *core_regs, crash_xen_core_t *xen_core_regs) { printk("STUB: " __FILE__ ": %s: not implemented\n", __FUNCTION__); diff --git a/xen/include/asm-x86/x86_32/elf.h b/xen/include/asm-x86/x86_32/elf.h index a70bd223f2..1aa4e07148 100644 --- a/xen/include/asm-x86/x86_32/elf.h +++ b/xen/include/asm-x86/x86_32/elf.h @@ -23,7 +23,7 @@ typedef struct { unsigned long ss; } ELF_Gregset; -extern inline void elf_core_save_regs(ELF_Gregset *core_regs, +static inline void elf_core_save_regs(ELF_Gregset *core_regs, crash_xen_core_t *xen_core_regs) { unsigned long tmp; diff --git a/xen/include/asm-x86/x86_64/elf.h b/xen/include/asm-x86/x86_64/elf.h index 75f191b43c..39c90b76f6 100644 --- a/xen/include/asm-x86/x86_64/elf.h +++ b/xen/include/asm-x86/x86_64/elf.h @@ -33,7 +33,7 @@ typedef struct { unsigned long gs; } ELF_Gregset; -extern inline void elf_core_save_regs(ELF_Gregset *core_regs, +static inline void elf_core_save_regs(ELF_Gregset *core_regs, crash_xen_core_t *xen_core_regs) { unsigned long tmp; From 11ae19768da209cc11cfb74189dd2dc908e573e5 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 14:30:42 +0000 Subject: [PATCH 145/282] Update hgignore list. --- .hgignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgignore b/.hgignore index a3e3bd2f20..b58e60bec5 100644 --- a/.hgignore +++ b/.hgignore @@ -158,6 +158,8 @@ ^tools/xcutils/xc_restore$ ^tools/xcutils/xc_save$ ^tools/xcutils/readnotes$ +^tools/xenfb/sdlfb$ +^tools/xenfb/vncfb$ ^tools/xenmon/xentrace_setmask$ ^tools/xenmon/xenbaked$ ^tools/xenstat/xentop/xentop$ From feeb19b8cbcea101a0c8e4195c51dfd11bff4388 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 14:35:33 +0000 Subject: [PATCH 146/282] [XEND] Fix missing vncpasswd option for HVM domains. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 375ba473a4..2b61760c1c 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -196,6 +196,7 @@ LEGACY_IMAGE_CFG = [ ('sdl', int), ('vncdisplay', int), ('vncunused', int), + ('vncpasswd', str), ] LEGACY_IMAGE_HVM_CFG = [ From b3312988255a7e0dc213bb4e11f533f8546fff0c Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 15:12:48 +0000 Subject: [PATCH 147/282] [TOOLS] Checks for libvncserver-dev and libsdl-dev. Signed-off-by: Alastair Tse --- tools/check/check_libvncserver | 21 +++++++++++++++++++++ tools/check/check_sdl | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100755 tools/check/check_libvncserver create mode 100755 tools/check/check_sdl diff --git a/tools/check/check_libvncserver b/tools/check/check_libvncserver new file mode 100755 index 0000000000..dc9ed9153d --- /dev/null +++ b/tools/check/check_libvncserver @@ -0,0 +1,21 @@ +#!/bin/sh +# CHECK-BUILD CHECK-INSTALL + +RC=0 + +LIBVNCSERVER_CONFIG="$(which libvncserver-config)" + +if test -z ${LIBVNCSERVER_CONFIG}; then + RC=1 +else + ${LIBVNCSERVER_CONFIG} --libs 2>&1 > /dev/null + RC=$? +fi + +if test $RC -ne 0; then + echo "FAILED" + echo " *** libvncserver-config is missing. " + echo " *** Please install libvncserver." +fi + +exit $RC diff --git a/tools/check/check_sdl b/tools/check/check_sdl new file mode 100755 index 0000000000..7832910355 --- /dev/null +++ b/tools/check/check_sdl @@ -0,0 +1,21 @@ +#!/bin/sh +# CHECK-BUILD CHECK-INSTALL + +RC=0 + +SDL_CONFIG="$(which sdl-config)" + +if test -z ${SDL_CONFIG}; then + RC=1 +else + ${SDL_CONFIG} --libs 2>&1 > /dev/null + RC=$? +fi + +if test $RC -ne 0; then + echo "FAILED" + echo " *** sdl-config is missing. " + echo " *** Please install libsdl-dev or sdl." +fi + +exit $RC From c7f32070aedd31b8e27a59cd01dfcfc4f9c55cd0 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 15:45:59 +0000 Subject: [PATCH 148/282] [HVM] Cache segment-register contents during PTE-update emulations. Also clean up page-fault propagation to inject the correct error code and CR2 value. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/svm/svm.c | 8 +++- xen/arch/x86/hvm/vmx/vmx.c | 8 +++- xen/arch/x86/mm/shadow/common.c | 67 +++++++++++++++++++----------- xen/arch/x86/mm/shadow/multi.c | 70 ++++++++++++++++---------------- xen/arch/x86/mm/shadow/private.h | 13 ++++++ xen/include/asm-x86/domain.h | 2 - xen/include/asm-x86/hvm/hvm.h | 7 ++-- xen/include/asm-x86/shadow.h | 8 ++-- 8 files changed, 113 insertions(+), 70 deletions(-) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index b95be55b80..5d19ae536c 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -812,9 +812,13 @@ static void svm_vcpu_destroy(struct vcpu *v) svm_destroy_vmcb(v); } -static void svm_hvm_inject_exception(unsigned int trapnr, int errcode) +static void svm_hvm_inject_exception( + unsigned int trapnr, int errcode, unsigned long cr2) { - svm_inject_exception(current, trapnr, (errcode != -1), errcode); + struct vcpu *v = current; + svm_inject_exception(v, trapnr, (errcode != -1), errcode); + if ( trapnr == TRAP_page_fault ) + v->arch.hvm_svm.vmcb->cr2 = v->arch.hvm_svm.cpu_cr2 = cr2; } int start_svm(void) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 556ea7b79f..aa6e364f6b 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -715,9 +715,13 @@ static void vmx_update_host_cr3(struct vcpu *v) __vmwrite(HOST_CR3, v->arch.cr3); } -static void vmx_inject_exception(unsigned int trapnr, int errcode) +static void vmx_inject_exception( + unsigned int trapnr, int errcode, unsigned long cr2) { - vmx_inject_hw_exception(current, trapnr, errcode); + struct vcpu *v = current; + vmx_inject_hw_exception(v, trapnr, errcode); + if ( trapnr == TRAP_page_fault ) + v->arch.hvm_vmx.cpu_cr2 = cr2; } /* Setup HVM interfaces */ diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 450dcd8ba0..5b6965a7f1 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -69,42 +69,52 @@ int _shadow_mode_refcounts(struct domain *d) /* x86 emulator support for the shadow code */ +struct segment_register *hvm_get_seg_reg( + enum x86_segment seg, struct sh_emulate_ctxt *sh_ctxt) +{ + struct segment_register *seg_reg = &sh_ctxt->seg_reg[seg]; + if ( !__test_and_set_bit(seg, &sh_ctxt->valid_seg_regs) ) + hvm_get_segment_register(current, seg, seg_reg); + return seg_reg; +} + static int hvm_translate_linear_addr( enum x86_segment seg, unsigned long offset, unsigned int bytes, unsigned int is_write, + struct sh_emulate_ctxt *sh_ctxt, unsigned long *paddr) { - struct segment_register creg, dreg; + struct segment_register *creg, *dreg; unsigned long limit, addr = offset; uint32_t last_byte; - hvm_get_segment_register(current, x86_seg_cs, &creg); - hvm_get_segment_register(current, seg, &dreg); + creg = hvm_get_seg_reg(x86_seg_cs, sh_ctxt); + dreg = hvm_get_seg_reg(seg, sh_ctxt); - if ( !creg.attr.fields.l || !hvm_long_mode_enabled(current) ) + if ( !creg->attr.fields.l || !hvm_long_mode_enabled(current) ) { /* * COMPATIBILITY MODE: Apply segment checks and add base. */ /* If this is a store, is the segment a writable data segment? */ - if ( is_write && ((dreg.attr.fields.type & 0xa) != 0x2) ) + if ( is_write && ((dreg->attr.fields.type & 0xa) != 0x2) ) goto gpf; /* Calculate the segment limit, including granularity flag. */ - limit = dreg.limit; - if ( dreg.attr.fields.g ) + limit = dreg->limit; + if ( dreg->attr.fields.g ) limit = (limit << 12) | 0xfff; last_byte = offset + bytes - 1; /* Is this a grows-down data segment? Special limit check if so. */ - if ( (dreg.attr.fields.type & 0xc) == 0x4 ) + if ( (dreg->attr.fields.type & 0xc) == 0x4 ) { /* Is upper limit 0xFFFF or 0xFFFFFFFF? */ - if ( !dreg.attr.fields.db ) + if ( !dreg->attr.fields.db ) last_byte = (uint16_t)last_byte; /* Check first byte and last byte against respective bounds. */ @@ -118,7 +128,7 @@ static int hvm_translate_linear_addr( * Hardware truncates to 32 bits in compatibility mode. * It does not truncate to 16 bits in 16-bit address-size mode. */ - addr = (uint32_t)(addr + dreg.base); + addr = (uint32_t)(addr + dreg->base); } else { @@ -127,7 +137,7 @@ static int hvm_translate_linear_addr( */ if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) ) - addr += dreg.base; + addr += dreg->base; if ( !is_canonical_address(addr) ) goto gpf; @@ -138,7 +148,7 @@ static int hvm_translate_linear_addr( gpf: /* Inject #GP(0). */ - hvm_inject_exception(TRAP_gp_fault, 0); + hvm_inject_exception(TRAP_gp_fault, 0, 0); return X86EMUL_PROPAGATE_FAULT; } @@ -149,10 +159,12 @@ sh_x86_emulate_read(enum x86_segment seg, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); unsigned long addr; - int rc; + int rc, errcode; - rc = hvm_translate_linear_addr(seg, offset, bytes, 0, &addr); + rc = hvm_translate_linear_addr(seg, offset, bytes, 0, sh_ctxt, &addr); if ( rc ) return rc; @@ -161,7 +173,7 @@ sh_x86_emulate_read(enum x86_segment seg, // It entirely ignores the permissions in the page tables. // In this case, that is only a user vs supervisor access check. // - if ( hvm_copy_from_guest_virt(val, addr, bytes) == 0 ) + if ( (rc = hvm_copy_from_guest_virt(val, addr, bytes)) == 0 ) { #if 0 struct vcpu *v = current; @@ -176,6 +188,8 @@ sh_x86_emulate_read(enum x86_segment seg, * was mapped here. This should never happen: we're here because * of a write fault at the end of the instruction we're emulating. */ SHADOW_PRINTK("read failed to va %#lx\n", addr); + errcode = ring_3(sh_ctxt->ctxt.regs) ? PFEC_user_mode : 0; + hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc); return X86EMUL_PROPAGATE_FAULT; } @@ -186,11 +200,13 @@ sh_x86_emulate_write(enum x86_segment seg, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); struct vcpu *v = current; unsigned long addr; int rc; - rc = hvm_translate_linear_addr(seg, offset, bytes, 1, &addr); + rc = hvm_translate_linear_addr(seg, offset, bytes, 1, sh_ctxt, &addr); if ( rc ) return rc; @@ -198,7 +214,8 @@ sh_x86_emulate_write(enum x86_segment seg, SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n", v->domain->domain_id, v->vcpu_id, addr, val, bytes); #endif - return v->arch.shadow.mode->x86_emulate_write(v, addr, &val, bytes, ctxt); + return v->arch.shadow.mode->x86_emulate_write( + v, addr, &val, bytes, sh_ctxt); } static int @@ -209,11 +226,13 @@ sh_x86_emulate_cmpxchg(enum x86_segment seg, unsigned int bytes, struct x86_emulate_ctxt *ctxt) { + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); struct vcpu *v = current; unsigned long addr; int rc; - rc = hvm_translate_linear_addr(seg, offset, bytes, 1, &addr); + rc = hvm_translate_linear_addr(seg, offset, bytes, 1, sh_ctxt, &addr); if ( rc ) return rc; @@ -221,8 +240,8 @@ sh_x86_emulate_cmpxchg(enum x86_segment seg, SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n", v->domain->domain_id, v->vcpu_id, addr, old, new, bytes); #endif - return v->arch.shadow.mode->x86_emulate_cmpxchg(v, addr, old, new, - bytes, ctxt); + return v->arch.shadow.mode->x86_emulate_cmpxchg( + v, addr, old, new, bytes, sh_ctxt); } static int @@ -234,11 +253,13 @@ sh_x86_emulate_cmpxchg8b(enum x86_segment seg, unsigned long new_hi, struct x86_emulate_ctxt *ctxt) { + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); struct vcpu *v = current; unsigned long addr; int rc; - rc = hvm_translate_linear_addr(seg, offset, 8, 1, &addr); + rc = hvm_translate_linear_addr(seg, offset, 8, 1, sh_ctxt, &addr); if ( rc ) return rc; @@ -247,8 +268,8 @@ sh_x86_emulate_cmpxchg8b(enum x86_segment seg, v->domain->domain_id, v->vcpu_id, addr, old_hi, old_lo, new_hi, new_lo, ctxt); #endif - return v->arch.shadow.mode->x86_emulate_cmpxchg8b(v, addr, old_lo, old_hi, - new_lo, new_hi, ctxt); + return v->arch.shadow.mode->x86_emulate_cmpxchg8b( + v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt); } diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 5dd6a84dd3..b3a0da43b0 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -2582,7 +2582,7 @@ static int sh_page_fault(struct vcpu *v, mfn_t gmfn, sl1mfn=_mfn(0); shadow_l1e_t sl1e, *ptr_sl1e; paddr_t gpa; - struct x86_emulate_ctxt emul_ctxt; + struct sh_emulate_ctxt emul_ctxt; int r, mmio; fetch_type_t ft = 0; @@ -2808,17 +2808,17 @@ static int sh_page_fault(struct vcpu *v, return EXCRET_fault_fixed; emulate: - /* Take the register set we were called with */ - if ( is_hvm_domain(d) ) - hvm_store_cpu_guest_regs(v, regs, NULL); - emul_ctxt.regs = regs; - emul_ctxt.mode = (is_hvm_domain(d) ? - hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST); + if ( !is_hvm_domain(d) ) + goto not_a_shadow_fault; + + hvm_store_cpu_guest_regs(v, regs, NULL); + emul_ctxt.ctxt.regs = regs; + emul_ctxt.ctxt.mode = (is_hvm_domain(d) ? + hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST); + emul_ctxt.valid_seg_regs = 0; SHADOW_PRINTK("emulate: eip=%#lx\n", regs->eip); - v->arch.shadow.propagate_fault = 0; - /* * We do not emulate user writes. Instead we use them as a hint that the * page is no longer a page table. This behaviour differs from native, but @@ -2826,7 +2826,7 @@ static int sh_page_fault(struct vcpu *v, * We also disallow guest PTE updates from within Xen. */ if ( (regs->error_code & PFEC_user_mode) || !guest_mode(regs) || - x86_emulate_memop(&emul_ctxt, &shadow_emulator_ops) ) + x86_emulate_memop(&emul_ctxt.ctxt, &shadow_emulator_ops) ) { SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n", mfn_x(gmfn)); @@ -2835,19 +2835,10 @@ static int sh_page_fault(struct vcpu *v, * to support more operations in the emulator. More likely, * though, this is a hint that this page should not be shadowed. */ shadow_remove_all_shadows(v, gmfn); - /* This means that actual missing operations will cause the - * guest to loop on the same page fault. */ - goto done; } - /* Emulation triggered another page fault? */ - if ( v->arch.shadow.propagate_fault ) - goto not_a_shadow_fault; - /* Emulator has changed the user registers: write back */ - if ( is_hvm_domain(d) ) - hvm_load_cpu_guest_regs(v, regs); - + hvm_load_cpu_guest_regs(v, regs); goto done; mmio: @@ -3786,11 +3777,11 @@ int sh_remove_l3_shadow(struct vcpu *v, mfn_t sl4mfn, mfn_t sl3mfn) * or NULL for error. */ static inline void * emulate_map_dest(struct vcpu *v, unsigned long vaddr, - struct x86_emulate_ctxt *ctxt, + struct sh_emulate_ctxt *sh_ctxt, mfn_t *mfnp) { walk_t gw; - u32 flags; + u32 flags, errcode; gfn_t gfn; mfn_t mfn; @@ -3801,13 +3792,17 @@ static inline void * emulate_map_dest(struct vcpu *v, sh_audit_gw(v, &gw); unmap_walk(v, &gw); - if ( !(flags & _PAGE_PRESENT) - || !(flags & _PAGE_RW) - || (!(flags & _PAGE_USER) && ring_3(ctxt->regs)) ) + if ( !(flags & _PAGE_PRESENT) ) { - /* This write would have faulted even on bare metal */ - v->arch.shadow.propagate_fault = 1; - return NULL; + errcode = 0; + goto page_fault; + } + + if ( !(flags & _PAGE_RW) || + (!(flags & _PAGE_USER) && ring_3(sh_ctxt->ctxt.regs)) ) + { + errcode = PFEC_page_present; + goto page_fault; } /* Attempted a write to a bad gfn? This should never happen: @@ -3817,11 +3812,18 @@ static inline void * emulate_map_dest(struct vcpu *v, ASSERT(sh_mfn_is_a_page_table(mfn)); *mfnp = mfn; return sh_map_domain_page(mfn) + (vaddr & ~PAGE_MASK); + + page_fault: + errcode |= PFEC_write_access; + if ( ring_3(sh_ctxt->ctxt.regs) ) + errcode |= PFEC_user_mode; + hvm_inject_exception(TRAP_page_fault, errcode, vaddr); + return NULL; } int sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src, - u32 bytes, struct x86_emulate_ctxt *ctxt) + u32 bytes, struct sh_emulate_ctxt *sh_ctxt) { mfn_t mfn; void *addr; @@ -3832,7 +3834,7 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src, ASSERT(shadow_lock_is_acquired(v->domain)); ASSERT(((vaddr & ~PAGE_MASK) + bytes) <= PAGE_SIZE); - if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL ) + if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL ) return X86EMUL_PROPAGATE_FAULT; memcpy(addr, src, bytes); @@ -3850,7 +3852,7 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src, int sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr, unsigned long old, unsigned long new, - unsigned int bytes, struct x86_emulate_ctxt *ctxt) + unsigned int bytes, struct sh_emulate_ctxt *sh_ctxt) { mfn_t mfn; void *addr; @@ -3863,7 +3865,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr, if ( vaddr & (bytes-1) ) return X86EMUL_UNHANDLEABLE; - if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL ) + if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL ) return X86EMUL_PROPAGATE_FAULT; switch ( bytes ) @@ -3899,7 +3901,7 @@ int sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr, unsigned long old_lo, unsigned long old_hi, unsigned long new_lo, unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) + struct sh_emulate_ctxt *sh_ctxt) { mfn_t mfn; void *addr; @@ -3911,7 +3913,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr, if ( vaddr & 7 ) return X86EMUL_UNHANDLEABLE; - if ( (addr = emulate_map_dest(v, vaddr, ctxt, &mfn)) == NULL ) + if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL ) return X86EMUL_PROPAGATE_FAULT; old = (((u64) old_hi) << 32) | (u64) old_lo; diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h index 61493b552d..c2c52d8f6a 100644 --- a/xen/arch/x86/mm/shadow/private.h +++ b/xen/arch/x86/mm/shadow/private.h @@ -506,6 +506,19 @@ static inline void sh_unpin(struct vcpu *v, mfn_t smfn) } } + +/**************************************************************************/ +/* PTE-write emulation. */ + +struct sh_emulate_ctxt { + struct x86_emulate_ctxt ctxt; + + /* Cache of segment registers already gathered for this emulation. */ + unsigned int valid_seg_regs; + struct segment_register seg_reg[6]; +}; + + #endif /* _XEN_SHADOW_PRIVATE_H */ /* diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 03620a33ac..a7b511fc32 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -147,8 +147,6 @@ struct shadow_vcpu { unsigned long last_writeable_pte_smfn; /* HVM guest: paging enabled (CR0.PG)? */ unsigned int translate_enabled:1; - /* Emulated fault needs to be propagated to guest? */ - unsigned int propagate_fault:1; }; struct arch_vcpu diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 1d2cc8bfdc..20373b0ec9 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -110,7 +110,8 @@ struct hvm_function_table { void (*stts)(struct vcpu *v); void (*set_tsc_offset)(struct vcpu *v, u64 offset); - void (*inject_exception)(unsigned int trapnr, int errcode); + void (*inject_exception)(unsigned int trapnr, int errcode, + unsigned long cr2); void (*init_ap_context)(struct vcpu_guest_context *ctxt, int vcpuid, int trampoline_vector); @@ -225,9 +226,9 @@ hvm_init_ap_context(struct vcpu_guest_context *ctxt, } static inline void -hvm_inject_exception(unsigned int trapnr, int errcode) +hvm_inject_exception(unsigned int trapnr, int errcode, unsigned long cr2) { - hvm_funcs.inject_exception(trapnr, errcode); + hvm_funcs.inject_exception(trapnr, errcode, cr2); } int hvm_bringup_ap(int vcpuid, int trampoline_vector); diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 7bf159b21d..78998edea9 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -246,7 +246,7 @@ shadow_vcpu_mode_translate(struct vcpu *v) /**************************************************************************/ /* Mode-specific entry points into the shadow code */ -struct x86_emulate_ctxt; +struct sh_emulate_ctxt; struct shadow_paging_mode { int (*page_fault )(struct vcpu *v, unsigned long va, struct cpu_user_regs *regs); @@ -267,18 +267,18 @@ struct shadow_paging_mode { void (*detach_old_tables )(struct vcpu *v); int (*x86_emulate_write )(struct vcpu *v, unsigned long va, void *src, u32 bytes, - struct x86_emulate_ctxt *ctxt); + struct sh_emulate_ctxt *sh_ctxt); int (*x86_emulate_cmpxchg )(struct vcpu *v, unsigned long va, unsigned long old, unsigned long new, unsigned int bytes, - struct x86_emulate_ctxt *ctxt); + struct sh_emulate_ctxt *sh_ctxt); int (*x86_emulate_cmpxchg8b )(struct vcpu *v, unsigned long va, unsigned long old_lo, unsigned long old_hi, unsigned long new_lo, unsigned long new_hi, - struct x86_emulate_ctxt *ctxt); + struct sh_emulate_ctxt *sh_ctxt); mfn_t (*make_monitor_table )(struct vcpu *v); void (*destroy_monitor_table )(struct vcpu *v, mfn_t mmfn); void * (*guest_map_l1e )(struct vcpu *v, unsigned long va, From 916bea06a7de9808785ed7da2039de4a33dd0a09 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 16:31:36 +0000 Subject: [PATCH 149/282] [XEND] Fix outputting device SXPs when domain is halted. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 2 +- tools/python/xen/xend/XendDomainInfo.py | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 2b61760c1c..698c4a3487 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -964,7 +964,7 @@ class XendConfig(dict): sxprs = [] pci_devs = [] - if 'devices' in self: + if 'devices' not in self: return sxprs for dev_type, dev_info in self['devices'].values(): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index dd8c2c3b27..0aa71fc4e6 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -580,8 +580,18 @@ class XendDomainInfo: return self.getDeviceController(deviceClass).destroyDevice(devid) + def getDeviceSxprs(self, deviceClass): - return self.getDeviceController(deviceClass).sxprs() + if self.state == DOM_STATE_RUNNING: + return self.getDeviceController(deviceClass).sxprs() + else: + sxprs = [] + dev_num = 0 + for dev_type, dev_info in self.info.all_devices_sxpr(): + if dev_type == deviceClass: + sxprs.append([dev_num, dev_info]) + dev_num += 1 + return sxprs def setMemoryTarget(self, target): From ed6af790ae8678fa9cea450ef141b37521ccd03c Mon Sep 17 00:00:00 2001 From: Andrew Warfield Date: Fri, 1 Dec 2006 09:01:04 -0800 Subject: [PATCH 150/282] Fix a number of flaws in the blktap userspace daemon when dealing with I/O errors. There are a number of flaws in the blktap userspace daemon when dealing with I/O errors. - The backends which use AIO check the io_events.res member to determine if an I/O error occurred. Which is good. But when calling the callback to signal completion of the I/O, they pass the io_events.res2 member Now this seems fine at first glance[1] "res is the usual result of an I/O operation: the number of bytes transfered, or a negative error code. res2 is a second status value which will be returned to the user" Except that "currently (2.6.0-test9), callers of aio_complete() within the kernel always set res2 to zero." And this hasn't changed anytime since 2.6.0, so by passing through the status from 'res2', the callback thinks the I/O operation succeeded even when it failed :-( The fix is simple instead of passing 'res2', just pass ep->res == io->u.c.nbytes ? 0 : 1 This would solve the error reporting to the guest, except that there is a second flaw... - The tapdisk I/O completion callback checks the status parameter passed in, syslog's it and then returns. It never bothers to send the I/O completion response back to the blktap kernel driver when a failure occurrs. Fortunately the fix for this is also simple. Instead of returning from the callback when dealing with an error, we simply toggle the status field for the pending response to BLKIF_RSP_ERROR and then continue with the normal codepath. So the error eventually gets back to the guest. The scenario I used to discover the problem and test the patch is thus: - In dom0 create a filesystem with only 200 MB of free space - Create a 1 GB sparse file on this volume. - Configure the guest so this sparse file appears as /dev/xvdb - In the domU create a single partition on /dev/xvdb and format it with ext3. - In the DomU, mount /dev/xvdb1 on /mnt and then run dd if=/dev/zero of=/mnt/data.bin bs=1GB count=1 Without this patch, the 'dd' command would succeed in writing 1 GB of data even though the underlying disk in Dom0 was only 200 MB in size. More complex tests of copying a whole directory heirarchy across resulted in catastrophic data corruption of the filessytem itself. Manual fsck was needed to fixup the filesystem & there were many very bad errors needing fixing. With this patch applied the DomU sees the I/O failures and kernel logs messages Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 722127 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 730327 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 738527 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 746727 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 754927 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 763127 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 771327 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 779527 Dec 1 11:02:53 dhcp-5-203 kernel: end_request: I/O error, dev xvdc, sector 792399 It will retry the I/O operation until it runs out of sectors to try, and then fail the operation. The filesystem is not seriously damaged - ext3 journal recovery will trivially cleanup if the guest is rebooted after the disk in Dom0 is enlarged. Signed-off-by: Daniel P. Berrange [1] http://lwn.net/Articles/24366/ --- tools/blktap/drivers/block-aio.c | 8 ++------ tools/blktap/drivers/block-qcow.c | 9 +-------- tools/blktap/drivers/tapdisk.c | 3 +-- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/tools/blktap/drivers/block-aio.c b/tools/blktap/drivers/block-aio.c index ca086b7faa..7f8dd5f773 100644 --- a/tools/blktap/drivers/block-aio.c +++ b/tools/blktap/drivers/block-aio.c @@ -311,12 +311,8 @@ int tdaio_do_callbacks(struct td_state *s, int sid) struct pending_aio *pio; pio = &prv->pending_aio[(long)io->data]; - - if (ep->res != io->u.c.nbytes) { - /* TODO: handle this case better. */ - DPRINTF("AIO did less than I asked it to. \n"); - } - rsp += pio->cb(s, ep->res2, pio->id, pio->private); + rsp += pio->cb(s, ep->res == io->u.c.nbytes ? 0 : 1, + pio->id, pio->private); prv->iocb_free[prv->iocb_free_count++] = io; } diff --git a/tools/blktap/drivers/block-qcow.c b/tools/blktap/drivers/block-qcow.c index d1c8777a2c..f7a57cd520 100644 --- a/tools/blktap/drivers/block-qcow.c +++ b/tools/blktap/drivers/block-qcow.c @@ -1145,13 +1145,6 @@ int tdqcow_do_callbacks(struct td_state *s, int sid) pio = &prv->pending_aio[(long)io->data]; - if (ep->res != io->u.c.nbytes) { - /* TODO: handle this case better. */ - ptr = (int *)&ep->res; - DPRINTF("AIO did less than I asked it to " - "[%lu,%lu,%d]\n", - ep->res, io->u.c.nbytes, *ptr); - } aio_unlock(prv, pio->sector); if (pio->id >= 0) { if (prv->crypt_method) @@ -1162,7 +1155,7 @@ int tdqcow_do_callbacks(struct td_state *s, int sid) &prv->aes_decrypt_key); prv->nr_reqs[pio->qcow_idx]--; if (prv->nr_reqs[pio->qcow_idx] == 0) - rsp += pio->cb(s, ep->res2, pio->id, + rsp += pio->cb(s, ep->res == io->u.c.nbytes ? 0 : 1, pio->id, pio->private); } else if (pio->id == -2) free(pio->buf); diff --git a/tools/blktap/drivers/tapdisk.c b/tools/blktap/drivers/tapdisk.c index 0c9b623abe..47d1e984a3 100644 --- a/tools/blktap/drivers/tapdisk.c +++ b/tools/blktap/drivers/tapdisk.c @@ -424,8 +424,7 @@ int send_responses(struct td_state *s, int res, int idx, void *private) } if (res != 0) { - DPRINTF("*** request error %d! \n", res); - return 0; + blkif->pending_list[idx].status = BLKIF_RSP_ERROR; } blkif->pending_list[idx].count--; From 123c8f3d8c7943aa492bb45eeec29dfe0dfb7e6e Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 17:21:19 +0000 Subject: [PATCH 151/282] [XEND] Fix case mismatch in VM.get_record for Xen API Also make VM.get_all return halted domains too. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendAPI.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 7970eff00d..9f3b2ed459 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -931,7 +931,7 @@ class XendAPI: # class methods def VM_get_all(self, session): - refs = [d.get_uuid() for d in XendDomain.instance().list()] + refs = [d.get_uuid() for d in XendDomain.instance().list('all')] return xen_api_success(refs) def VM_get_by_name_label(self, session, label): @@ -966,14 +966,14 @@ class XendAPI: 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(), 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(), 'memory_actual': xeninfo.get_memory_static_min(), - 'vcpus_policy': xeninfo.get_vcpus_policy(), - 'vcpus_params': xeninfo.get_vcpus_params(), - 'vcpus_number': xeninfo.getVCpuCount(), - 'vcpus_utilisation': xeninfo.get_vcpus_util(), - 'vcpus_features_required': [], - 'vcpus_features_can_use': [], - 'vcpus_features_force_on': [], - 'vcpus_features_force_off': [], + 'VCPUs_policy': xeninfo.get_vcpus_policy(), + 'VCPUs_params': xeninfo.get_vcpus_params(), + 'VCPUs_number': xeninfo.getVCpuCount(), + 'VCPUs_utilisation': xeninfo.get_vcpus_util(), + 'VCPUs_features_required': [], + 'VCPUs_features_can_use': [], + 'VCPUs_features_force_on': [], + 'VCPUs_features_force_off': [], 'actions_after_shutdown': xeninfo.get_on_shutdown(), 'actions_after_reboot': xeninfo.get_on_reboot(), 'actions_after_suspend': xeninfo.get_on_suspend(), From 1016756b1dc2a0071b4f09ccd45e05910fcae9ae Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 1 Dec 2006 17:29:04 +0000 Subject: [PATCH 152/282] [XEN] Allow shutdown code to be set at most once per domain. SIgned-off-by: Keir Fraser --- xen/common/domain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/common/domain.c b/xen/common/domain.c index 238ee037a7..51a2e78d31 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -283,8 +283,8 @@ void domain_shutdown(struct domain *d, u8 reason) if ( d->domain_id == 0 ) dom0_shutdown(reason); - d->shutdown_code = reason; - set_bit(_DOMF_shutdown, &d->domain_flags); + if ( !test_and_set_bit(_DOMF_shutdown, &d->domain_flags) ) + d->shutdown_code = reason; for_each_vcpu ( d, v ) vcpu_sleep_nosync(v); From 486d848417aae8583ae7676618010410a8305f1c Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 17:30:39 +0000 Subject: [PATCH 153/282] [XEND] Proper importing of Xen API VM Struct into new XendConfig Use a smarter method of importing the Xen API VM struct when adding to XendConfig. Also add a commented __setitem__ override for XendConfig to type check certain configuration values. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 35 +++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 698c4a3487..5733abf34c 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -106,7 +106,7 @@ XENAPI_CFG_TYPES = { 'platform_clock_offset': bool0, 'platform_enable_audio': bool0, 'platform_keymap': str, - 'boot_method': int, + 'boot_method': str, 'builder': str, 'kernel_kernel': str, 'kernel_initrd': str, @@ -263,7 +263,7 @@ class XendConfig(dict): self._sxp_to_xapi(sxp_obj) self._sxp_to_xapi_unsupported(sxp_obj) elif xapi: - self.update(xapi) + self.update_with_xenapi_config(xapi) self._add_xapi_unsupported() elif dominfo: # output from xc.domain_getinfo @@ -274,6 +274,21 @@ class XendConfig(dict): # validators go here self.validate() + """ In time, we should enable this type checking addition. It is great + also for tracking bugs and unintended writes to XendDomainInfo.info + def __setitem__(self, key, value): + type_conv = XENAPI_CFG_TYPES.get(key) + if callable(type_conv): + try: + dict.__setitem__(self, key, type_conv(value)) + except (ValueError, TypeError): + raise XendConfigError("Wrong type for configuration value " + + "%s. Expected %s" % + (key, type_conv.__name__)) + else: + dict.__setitem__(self, key, value) + """ + def _defaults(self): defaults = { 'uuid': uuid.createString(), @@ -715,6 +730,22 @@ class XendConfig(dict): self._dominfo_to_xapi(dominfo) self.validate() + def update_with_xenapi_config(self, xapi): + """Update configuration with a Xen API VM struct + + @param xapi: Xen API VM Struct + @type xapi: dict + """ + for key, val in xapi.items(): + key = key.lower() + type_conv = XENAPI_CFG_TYPES.get(key) + if callable(type_conv): + self[key] = type_conv(val) + else: + self[key] = val + + self.validate() + def to_xml(self): """Return an XML string representing the configuration.""" pass From 0ee9d7cc2975f35bebf15b3da8f587447e7f3d27 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 17:31:30 +0000 Subject: [PATCH 154/282] [XENAPI] Add extra param for VM.start and fix case for printing out the output of VM.get_record. Signed-off-by: Alastair Tse --- tools/python/scripts/xapi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py index 7eb96e8945..07d886698b 100644 --- a/tools/python/scripts/xapi.py +++ b/tools/python/scripts/xapi.py @@ -29,7 +29,7 @@ from getpass import getpass MB = 1024 * 1024 HOST_INFO_FORMAT = '%-20s: %-50s' -VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(vcpus_number)-5s'\ +VM_LIST_FORMAT = '%(name_label)-18s %(memory_actual)-5s %(VCPUs_number)-5s'\ ' %(power_state)-10s %(uuid)-36s' SR_LIST_FORMAT = '%(name_label)-18s %(uuid)-36s %(physical_size)-10s' \ '%(type)-10s' @@ -226,7 +226,7 @@ def xapi_vm_list(*args): if not is_long: print VM_LIST_FORMAT % {'name_label':'Name', 'memory_actual':'Mem', - 'vcpus_number': 'VCPUs', + 'VCPUs_number': 'VCPUs', 'power_state': 'State', 'uuid': 'UUID'} @@ -286,7 +286,7 @@ def xapi_vm_start(*args): server, session = _connect() vm_uuid = resolve_vm(server, session, args[0]) print 'Starting VM %s (%s)' % (args[0], vm_uuid) - success = execute(server.VM.start, session, vm_uuid) + success = execute(server.VM.start, session, vm_uuid, False) print 'Done.' def xapi_vm_shutdown(*args): From cebaab7c6b90391742eafd652c4aebc59f0e9052 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 17:37:09 +0000 Subject: [PATCH 155/282] This patch provides XmTestManagedDomain and XenManagedDomain classes similar to the XmTestDomain and XenDomain classes. I have wrapped the xen-api for VM configuration creation, starting and stopping of VMs and destruction of the VM configuration in the XenManagedDomain class's methods. No device-related functions are provided through the class. The managed domains' UUIDs are tracked and all created VMs are destroyed upon failure or skipping of the test or by calling xapi.vm_destroy_all(). I am adding a new grouptest 'xapi' for running xen-api tests. Only caveat: I am using an empty username and password (XmTestList/xapi.py) with Xend's authentication deactivated to run these tests. Signed-off-by: Stefan Berger --- tools/python/scripts/xapi.py | 11 -- tools/xm-test/grouptest/xapi | 1 + tools/xm-test/lib/XmTestLib/Test.py | 3 + .../xm-test/lib/XmTestLib/XenManagedDomain.py | 176 ++++++++++++++++++ tools/xm-test/lib/XmTestLib/xapi.py | 66 +++++++ tools/xm-test/tests/vtpm/09_vtpm-xapi.py | 76 ++++++++ tools/xm-test/tests/vtpm/Makefile.am | 3 +- 7 files changed, 324 insertions(+), 12 deletions(-) create mode 100644 tools/xm-test/grouptest/xapi create mode 100644 tools/xm-test/lib/XmTestLib/XenManagedDomain.py create mode 100644 tools/xm-test/lib/XmTestLib/xapi.py create mode 100644 tools/xm-test/tests/vtpm/09_vtpm-xapi.py diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py index 07d886698b..cf2b0aa78a 100644 --- a/tools/python/scripts/xapi.py +++ b/tools/python/scripts/xapi.py @@ -438,17 +438,6 @@ def xapi_vtpm_create(*args): print "Creating vTPM with cfg = %s" % cfg vtpm_uuid = execute(server.VTPM.create, session, cfg) print "Done. (%s)" % vtpm_uuid - vtpm_id = execute(server.VTPM.get_instance, session, vtpm_uuid) - print "Has instance number '%s'" % vtpm_id - vtpm_be = execute(server.VTPM.get_backend, session, vtpm_uuid) - print "Has backend in '%s'" % vtpm_be - driver = execute(server.VTPM.get_driver, session, vtpm_uuid) - print "Has driver type '%s'" % driver - vtpm_rec = execute(server.VTPM.get_record, session, vtpm_uuid) - print "Has vtpm record '%s'" % vtpm_rec - vm = execute(server.VTPM.get_VM, session, vtpm_uuid) - print "Has VM '%s'" % vm - # # Command Line Utils diff --git a/tools/xm-test/grouptest/xapi b/tools/xm-test/grouptest/xapi new file mode 100644 index 0000000000..407368e6b4 --- /dev/null +++ b/tools/xm-test/grouptest/xapi @@ -0,0 +1 @@ +vtpm 09_vtpm-xapi.test diff --git a/tools/xm-test/lib/XmTestLib/Test.py b/tools/xm-test/lib/XmTestLib/Test.py index 68a176c273..7efbc0f3e3 100644 --- a/tools/xm-test/lib/XmTestLib/Test.py +++ b/tools/xm-test/lib/XmTestLib/Test.py @@ -33,6 +33,7 @@ import select import signal import re import glob +import xapi TEST_PASS = 0 TEST_FAIL = 255 @@ -133,10 +134,12 @@ def becomeNonRoot(): def FAIL(format, *args): print "\nREASON:", (format % args) + xapi.vm_destroy_all() sys.exit(TEST_FAIL) def SKIP(format, *args): print "\nREASON:", (format % args) + xapi.vm_destroy_all() sys.exit(TEST_SKIP) def saveLog(logText, filename=None): diff --git a/tools/xm-test/lib/XmTestLib/XenManagedDomain.py b/tools/xm-test/lib/XmTestLib/XenManagedDomain.py new file mode 100644 index 0000000000..94fbe44d3e --- /dev/null +++ b/tools/xm-test/lib/XmTestLib/XenManagedDomain.py @@ -0,0 +1,176 @@ +#!/usr/bin/python +""" + Copyright (C) International Business Machines Corp., 2005 + Author: Stefan Berger + + Based on XenDomain.py by Dan Smith + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; under version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +import os +import sys +from XmTestLib import * +from xen.util.xmlrpclib2 import ServerProxy +from types import DictType + + +class XenManagedConfig: + """An object to help create a VM configuration usable via Xen-API""" + def __init__(self): + self.opts = {} + #Array to translate old option to new ones + self.opttrlate = { 'name' : 'name_label' , + 'memory' : [ 'memory_static_max' , + 'memory_static_min' , + 'memory_dynamic_min', + 'memory_dynamic_max' ], + 'kernel' : 'kernel_kernel', + 'ramdisk': 'kernel_initrd', + 'root' : 'kernel_args'} + + def setOpt(self, name, value): + """Set an option in the config""" + if name in self.opttrlate.keys(): + _name = self.opttrlate[name] + else: + _name = name + + if isinstance(_name, list): + for _n in _name: + self.opts[_n] = value + else: + self.opts[_name] = value + + def getOpt(self, name): + """Return the value of a config option""" + if name in self.opts.keys(): + return self.opts[name] + else: + return None + + def setOpts(self, opts): + """Batch-set options from a dictionary""" + for k, v in opts.items(): + self.setOpt(k, v) + + def getOpts(self): + return self.opts + + +class XenManagedDomain(XenDomain): + + def __init__(self, name=None, config=None): + if name: + self.name = name + else: + self.name = getUniqueName() + + self.config = config + self.console = None + self.netEnv = "bridge" + + self.server, self.session = xapi._connect() + server = self.server + try: + self.vm_uuid = xapi.execute(server.VM.create, self.session, + self.config.getOpts()) + xapi._VMuuids.append(self.vm_uuid) + except: + raise DomainError("Could not create VM config file for " + "managed domain.") + + #Only support PV for now. + self.type = "PV" + + def start(self, noConsole=False): + #start the VM + server = self.server + if self.vm_uuid: + try: + xapi.execute(server.VM.start, self.session, self.vm_uuid) + except: + raise DomainError("Could not start domain") + else: + raise DomainError("VM has not UUID - VM config does not exist?") + + if self.getDomainType() == "HVM": + waitForBoot() + + if self.console and noConsole == True: + self.closeConsole() + + elif self.console and noConsole == False: + return self.console + + elif not self.console and noConsole == False: + return self.getConsole() + + def stop(self): + if self.vm_uuid: + server = self.server + xapi.execute(server.VM.hard_shutdown, self.session, self.vm_uuid) + else: + raise DomainError("VM has not UUID - VM config does not exist?") + + def destroy(self): + #Stop VM first. + self.stop() + if self.vm_uuid: + server = self.server + xapi.execute(server.VM.destroy, self.session, self.vm_uuid) + xapi._VMuuids.remove(self.vm_uuid) + else: + raise DomainError("VM has not UUID - VM config does not exist?") + + def get_uuid(self): + return self.vm_uuid + + def newDevice(self, Device, *args): + raise DomainError("No support for newDevice().") + + def removeDevice(self, id): + raise DomainError("No support for removeDevice().") + + def removeAllDevices(self, id): + raise DomainError("No support for removeAllDevices().") + + def isRunning(self): + return isDomainRunning(self.name) + + def getDevice(self, id): + raise DomainError("No support for getDevice().") + + +class XmTestManagedDomain(XenManagedDomain): + + """Create a new managed xm-test domain + @param name: The requested domain name + @param extraConfig: Additional configuration options + @param baseConfig: The initial configuration defaults to use + """ + def __init__(self, name=None, extraConfig=None, + baseConfig=arch.configDefaults): + config = XenManagedConfig() + config.setOpts(baseConfig) + if extraConfig: + config.setOpts(extraConfig) + + if name: + config.setOpt("name_label", name) + elif not config.getOpt("name_label"): + config.setOpt("name_label", getUniqueName()) + + XenManagedDomain.__init__(self, config.getOpt("name_label"), + config=config) diff --git a/tools/xm-test/lib/XmTestLib/xapi.py b/tools/xm-test/lib/XmTestLib/xapi.py new file mode 100644 index 0000000000..2a9ec209e3 --- /dev/null +++ b/tools/xm-test/lib/XmTestLib/xapi.py @@ -0,0 +1,66 @@ +#!/usr/bin/python +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006 XenSource Ltd. +# Copyright (C) 2006 IBM Corporation +#============================================================================ + +import os +import sys +from XmTestLib import * +from xen.util.xmlrpclib2 import ServerProxy +from types import DictType + + +XAPI_DEFAULT_LOGIN = " " +XAPI_DEFAULT_PASSWORD = " " + +class XenAPIError(Exception): + pass + + +#A list of VMs' UUIDs that were created using vm_create +_VMuuids = [] + +#Terminate previously created managed(!) VMs and destroy their configs +def vm_destroy_all(): + server, session = _connect() + for uuid in _VMuuids: + execute(server.VM.hard_shutdown, session, uuid) + execute(server.VM.destroy , session, uuid) + + +def execute(fn, *args): + result = fn(*args) + if type(result) != DictType: + raise TypeError("Function returned object of type: %s" % + str(type(result))) + if 'Value' not in result: + raise XenAPIError(*result['ErrorDescription']) + return result['Value'] + +_initialised = False +_server = None +_session = None +def _connect(*args): + global _server, _session, _initialised + if not _initialised: + _server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock') + login = XAPI_DEFAULT_LOGIN + password = XAPI_DEFAULT_PASSWORD + creds = (login, password) + _session = execute(_server.session.login_with_password, *creds) + _initialised = True + return (_server, _session) diff --git a/tools/xm-test/tests/vtpm/09_vtpm-xapi.py b/tools/xm-test/tests/vtpm/09_vtpm-xapi.py new file mode 100644 index 0000000000..8547a08b03 --- /dev/null +++ b/tools/xm-test/tests/vtpm/09_vtpm-xapi.py @@ -0,0 +1,76 @@ +#!/usr/bin/python + +# Copyright (C) International Business Machines Corp., 2006 +# Author: Stefan Berger + +# Test to test the vtpm class through the Xen-API + +from XmTestLib import xapi +from XmTestLib.XenManagedDomain import XmTestManagedDomain +from XmTestLib import * +from vtpm_utils import * +import commands +import os + +def do_test(): + domain = XmTestManagedDomain() + vm_uuid = domain.get_uuid() + + vtpmcfg = {} + vtpmcfg['type'] = "paravirtualised" + vtpmcfg['backend'] = "Domain-0" + vtpmcfg['instance'] = 1 + vtpmcfg['VM'] = vm_uuid + + server, session = xapi._connect() + + vtpm_uuid = xapi.execute(server.VTPM.create, session, vtpmcfg) + + vtpm_id = xapi.execute(server.VTPM.get_instance, session, vtpm_uuid) + vtpm_be = xapi.execute(server.VTPM.get_backend , session, vtpm_uuid) + if vtpm_be != vtpmcfg['backend']: + FAIL("vTPM's backend is in '%s', expected: '%s'" % + (vtpm_be, vtpmcfg['backend'])) + + driver = xapi.execute(server.VTPM.get_driver, session, vtpm_uuid) + if driver != vtpmcfg['type']: + FAIL("vTPM has driver type '%s', expected: '%s'" % + (driver, vtpmcfg['type'])) + + vtpm_rec = xapi.execute(server.VTPM.get_record, session, vtpm_uuid) + + if vtpm_rec['driver'] != vtpmcfg['type']: + FAIL("vTPM record shows driver type '%s', expected: '%s'" % + (vtpm_rec['driver'], vtpmcfg['type'])) + if vtpm_rec['uuid'] != vtpm_uuid: + FAIL("vTPM record shows vtpm uuid '%s', expected: '%s'" % + (vtpm_rec['uuid'], vtpm_uuid)) + if vtpm_rec['VM'] != vm_uuid: + FAIL("vTPM record shows VM uuid '%s', expected: '%s'" % + (vtpm_rec['VM'], vm_uuid)) + + success = domain.start() + + console = domain.getConsole() + + try: + run = console.runCmd("cat /sys/devices/xen/vtpm-0/pcrs") + except ConsoleError, e: + saveLog(console.getHistory()) + vtpm_cleanup(domName) + FAIL("No result from dumping the PCRs") + + if re.search("No such file",run["output"]): + vtpm_cleanup(domName) + FAIL("TPM frontend support not compiled into (domU?) kernel") + + domain.stop() + domain.destroy() + + + +try: + do_test() +finally: + #Make sure all domains are gone that were created in this test case + xapi.vm_destroy_all() diff --git a/tools/xm-test/tests/vtpm/Makefile.am b/tools/xm-test/tests/vtpm/Makefile.am index d6aae0c15b..dd67e459ec 100644 --- a/tools/xm-test/tests/vtpm/Makefile.am +++ b/tools/xm-test/tests/vtpm/Makefile.am @@ -7,7 +7,8 @@ TESTS = 01_vtpm-list_pos.test \ 05_vtpm-loc_migr.test \ 06_vtpm-susp_res_pcrs.test \ 07_vtpm-mig_pcrs.test \ - 08_vtpm-mig_pcrs.test + 08_vtpm-mig_pcrs.test \ + 09_vtpm-xapi.test XFAIL_TESTS = From 0f07569d157834b25a67ff49bf68fb46932a206f Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 17:37:42 +0000 Subject: [PATCH 156/282] [XEND] Re-add vtpm device support in XendConfig This patch re-adds a recently removed vTPM device handling code. I am also removing that one code part in the test script that does not work. Signed-off-by: Stefan Berger --- tools/python/scripts/xapi.py | 2 -- tools/python/xen/xend/XendConfig.py | 12 +++++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/tools/python/scripts/xapi.py b/tools/python/scripts/xapi.py index 07d886698b..06baeefe4c 100644 --- a/tools/python/scripts/xapi.py +++ b/tools/python/scripts/xapi.py @@ -446,8 +446,6 @@ def xapi_vtpm_create(*args): print "Has driver type '%s'" % driver vtpm_rec = execute(server.VTPM.get_record, session, vtpm_uuid) print "Has vtpm record '%s'" % vtpm_rec - vm = execute(server.VTPM.get_VM, session, vtpm_uuid) - print "Has VM '%s'" % vm # diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 5733abf34c..3e4df3183f 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -945,7 +945,17 @@ class XendConfig(dict): self['devices'][dev_uuid] = (dev_type, dev_info) self['vbd_refs'].append(dev_uuid) return dev_uuid - + + elif dev_type in ('vtpm'): + if cfg_xenapi.get('type'): + dev_info['type'] = cfg_xenapi.get('type') + + dev_uuid = cfg_xenapi.get('uuid', uuid.createString()) + dev_info['uuid'] = dev_uuid + self['devices'][dev_uuid] = (dev_type, dev_info) + self['vtpm_refs'].append(dev_uuid) + return dev_uuid + return '' def device_update(self, dev_uuid, cfg_sxp): From 468c5c0084f93c57fec838ee4102729d68623a6a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 1 Dec 2006 17:40:07 +0000 Subject: [PATCH 157/282] Use the new xen-api.sock for the calls to the Xen-API server. Signed-off-by: Ewan Mellor --- tools/xm-test/lib/XmTestLib/xapi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/xm-test/lib/XmTestLib/xapi.py b/tools/xm-test/lib/XmTestLib/xapi.py index 2a9ec209e3..bab0e103d9 100644 --- a/tools/xm-test/lib/XmTestLib/xapi.py +++ b/tools/xm-test/lib/XmTestLib/xapi.py @@ -57,7 +57,7 @@ _session = None def _connect(*args): global _server, _session, _initialised if not _initialised: - _server = ServerProxy('httpu:///var/run/xend/xmlrpc.sock') + _server = ServerProxy('httpu:///var/run/xend/xen-api.sock') login = XAPI_DEFAULT_LOGIN password = XAPI_DEFAULT_PASSWORD creds = (login, password) From cd1496c790bc383db7cddee5e9d67297dc56a167 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Fri, 1 Dec 2006 11:12:00 -0700 Subject: [PATCH 158/282] [IA64] Check CPL for break 0x80001 case This is a patch which intends for fixing ltrace problem. When I execute a command "ltrace ps" on dom0, it makes dom0 hung. It comes from "break 0x80001" is shared by ltrace(CPL=3) and hpsim(CPL=2). To avoid this problem, I just add check CPL in ia64_break_fault code. Signed-off-by: Atsushi SAKAI --- xen/arch/ia64/xen/faults.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/xen/faults.c b/xen/arch/ia64/xen/faults.c index 05aea16fc2..741800fa70 100644 --- a/xen/arch/ia64/xen/faults.c +++ b/xen/arch/ia64/xen/faults.c @@ -524,7 +524,9 @@ ia64_handle_break(unsigned long ifa, struct pt_regs *regs, unsigned long isr, struct vcpu *v = current; IA64FAULT vector; - if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant + /* FIXME: don't hardcode constant */ + if ((iim == 0x80001 || iim == 0x80002) + && ia64_get_cpl(regs->cr_ipsr) == 2) { do_ssc(vcpu_get_gr(current, 36), regs); } #ifdef CRASH_DEBUG From 63f6456e927eb6a356291e7147a5de1deceb9c8a Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 18:33:11 +0000 Subject: [PATCH 159/282] Merge --- tools/xm-test/lib/XmTestReport/OSReport.py | 0 tools/xm-test/lib/XmTestReport/ProgReport.py | 0 tools/xm-test/lib/XmTestReport/Report.py | 0 tools/xm-test/lib/XmTestReport/ResultReport.py | 0 tools/xm-test/lib/XmTestReport/arch.py | 0 tools/xm-test/lib/XmTestReport/utils.py | 0 tools/xm-test/lib/XmTestReport/xmtest.py.in | 0 tools/xm-test/mergereport | 0 tools/xm-test/mkreport | 0 9 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/OSReport.py mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/ProgReport.py mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/Report.py mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/ResultReport.py mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/arch.py mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/utils.py mode change 100644 => 100755 tools/xm-test/lib/XmTestReport/xmtest.py.in mode change 100644 => 100755 tools/xm-test/mergereport mode change 100644 => 100755 tools/xm-test/mkreport diff --git a/tools/xm-test/lib/XmTestReport/OSReport.py b/tools/xm-test/lib/XmTestReport/OSReport.py old mode 100644 new mode 100755 diff --git a/tools/xm-test/lib/XmTestReport/ProgReport.py b/tools/xm-test/lib/XmTestReport/ProgReport.py old mode 100644 new mode 100755 diff --git a/tools/xm-test/lib/XmTestReport/Report.py b/tools/xm-test/lib/XmTestReport/Report.py old mode 100644 new mode 100755 diff --git a/tools/xm-test/lib/XmTestReport/ResultReport.py b/tools/xm-test/lib/XmTestReport/ResultReport.py old mode 100644 new mode 100755 diff --git a/tools/xm-test/lib/XmTestReport/arch.py b/tools/xm-test/lib/XmTestReport/arch.py old mode 100644 new mode 100755 diff --git a/tools/xm-test/lib/XmTestReport/utils.py b/tools/xm-test/lib/XmTestReport/utils.py old mode 100644 new mode 100755 diff --git a/tools/xm-test/lib/XmTestReport/xmtest.py.in b/tools/xm-test/lib/XmTestReport/xmtest.py.in old mode 100644 new mode 100755 diff --git a/tools/xm-test/mergereport b/tools/xm-test/mergereport old mode 100644 new mode 100755 diff --git a/tools/xm-test/mkreport b/tools/xm-test/mkreport old mode 100644 new mode 100755 From f24b8a3348b6f787d2215b847f9e2d73f17bad36 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 1 Dec 2006 18:35:19 +0000 Subject: [PATCH 160/282] [XEND] Fix mis-types in XendConfig Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 3e4df3183f..5a06f77efb 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -75,11 +75,11 @@ XENAPI_HVM_CFG = { XENAPI_CFG_TYPES = { 'uuid': str, - 'power_state': int, + 'power_state': str, 'name_label': str, 'name_description': str, 'user_version': str, - 'is_a_template': int, + 'is_a_template': bool0, 'resident_on': str, 'memory_static_min': int, 'memory_static_max': int, From d8b39738aac005c8822e0d78c021db8c3e69451f Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Fri, 1 Dec 2006 11:40:57 -0700 Subject: [PATCH 161/282] [IA64] Change to new interrupt deliver mechanism. Signed-off-by: Anthony Xu --- .../arch/ia64/xen/xcom_privcmd.c | 11 +- tools/ioemu/Makefile.target | 4 +- xen/arch/ia64/vmx/viosapic.c | 67 ++++-------- xen/arch/ia64/vmx/vmx_hypercall.c | 101 ++++++++++++++---- xen/include/asm-ia64/viosapic.h | 12 +-- 5 files changed, 116 insertions(+), 79 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c index 51cbb9f4c0..0f5fccdac7 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c @@ -579,9 +579,16 @@ xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall) case HVMOP_set_param: argsize = sizeof(xen_hvm_param_t); break; - case HVMOP_set_irq_level: - argsize = sizeof(xen_hvm_set_irq_level_t); + case HVMOP_set_pci_intx_level: + argsize = sizeof(xen_hvm_set_pci_intx_level_t); break; + case HVMOP_set_isa_irq_level: + argsize = sizeof(xen_hvm_set_isa_irq_level_t); + break; + case HVMOP_set_pci_link_route: + argsize = sizeof(xen_hvm_set_pci_link_route_t); + break; + default: printk("%s: unknown HVMOP %d\n", __func__, cmd); return -EINVAL; diff --git a/tools/ioemu/Makefile.target b/tools/ioemu/Makefile.target index b35cdbaeb5..4872128d20 100644 --- a/tools/ioemu/Makefile.target +++ b/tools/ioemu/Makefile.target @@ -296,7 +296,7 @@ endif # qemu-dm objects ifeq ($(ARCH),ia64) -LIBOBJS=helper2.o exec-dm.o i8259-dm.o +LIBOBJS=helper2.o exec-dm.o i8259-dm.o piix_pci-dm.o else LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o piix_pci-dm.o endif @@ -360,7 +360,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) ifeq ($(ARCH),ia64) -VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o piix_pci.o +VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o else VL_OBJS+= fdc.o serial.o pc.o endif diff --git a/xen/arch/ia64/vmx/viosapic.c b/xen/arch/ia64/vmx/viosapic.c index 8a06ec6046..49894291bb 100644 --- a/xen/arch/ia64/vmx/viosapic.c +++ b/xen/arch/ia64/vmx/viosapic.c @@ -70,9 +70,12 @@ static void viosapic_deliver(struct viosapic *viosapic, int irq) static int iosapic_get_highest_irq(struct viosapic *viosapic) { - uint32_t irqs = viosapic->irr | viosapic->irr_xen; - irqs &= ~viosapic->isr & ~viosapic->imr; - return fls(irqs) - 1; + uint64_t irqs = viosapic->irr & ~viosapic->isr ; + + if (irqs >> 32) + return (fls(irqs >> 32) - 1 + 32); + else + return fls(irqs) - 1; } @@ -95,14 +98,12 @@ static void service_iosapic(struct viosapic *viosapic) while ( (irq = iosapic_get_highest_irq(viosapic)) != -1 ) { - if ( !test_bit(irq, &viosapic->imr) ) - viosapic_deliver(viosapic, irq); + viosapic_deliver(viosapic, irq); if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL ) - viosapic->isr |= (1 << irq); + viosapic->isr |= (1UL << irq); - viosapic->irr &= ~(1 << irq); - viosapic->irr_xen &= ~(1 << irq); + viosapic->irr &= ~(1UL << irq); } } @@ -192,15 +193,6 @@ unsigned long viosapic_read(struct vcpu *v, } -static inline void viosapic_update_imr(struct viosapic *viosapic, int index) -{ - if ( viosapic->redirtbl[index].mask ) - set_bit(index, &viosapic->imr); - else - clear_bit(index, &viosapic->imr); -} - - static void viosapic_write_indirect(struct viosapic *viosapic, unsigned long addr, unsigned long length, @@ -237,7 +229,6 @@ static void viosapic_write_indirect(struct viosapic *viosapic, (val & 0xffffffff); } viosapic->redirtbl[redir_index].bits = redir_content; - viosapic_update_imr(viosapic, redir_index); break; } } /* switch */ @@ -282,39 +273,14 @@ static void viosapic_reset(struct viosapic *viosapic) for ( i = 0; i < VIOSAPIC_NUM_PINS; i++ ) { viosapic->redirtbl[i].mask = 0x1; - viosapic_update_imr(viosapic, i); } spin_lock_init(&viosapic->lock); } - -// this is used by VBD/VNIF to inject interrupt for VTI-domain -void viosapic_set_xen_irq(struct domain *d, int irq, int level) -{ - struct viosapic *viosapic = domain_viosapic(d); - - spin_lock(&viosapic->lock); - if ( viosapic->redirtbl[irq].mask ) - goto out; - - if ( viosapic->redirtbl[irq].trig_mode == SAPIC_EDGE) - gdprintk(XENLOG_WARNING, "Forcing edge triggered APIC irq %d?\n", irq); - - if ( level ) - viosapic->irr_xen |= 1 << irq; - else - viosapic->irr_xen &= ~(1 << irq); - - service_iosapic(viosapic); -out: - spin_unlock(&viosapic->lock); -} - - void viosapic_set_irq(struct domain *d, int irq, int level) { struct viosapic *viosapic = domain_viosapic(d); - uint32_t bit; + uint64_t bit; spin_lock(&viosapic->lock); if ( (irq < 0) || (irq >= VIOSAPIC_NUM_PINS) ) @@ -323,7 +289,7 @@ void viosapic_set_irq(struct domain *d, int irq, int level) if ( viosapic->redirtbl[irq].mask ) goto out; - bit = 1 << irq; + bit = 1UL << irq; if ( viosapic->redirtbl[irq].trig_mode == SAPIC_LEVEL ) { if ( level ) @@ -343,6 +309,17 @@ out: spin_unlock(&viosapic->lock); } +#define hvm_pci_intx_gsi(dev, intx) \ + (((((dev) << 2) + ((dev) >> 3) + (intx)) & 31) + 16) + + +void viosapic_set_pci_irq(struct domain *d, int device, int intx, int level) +{ + int irq; + irq = hvm_pci_intx_gsi(device, intx); + + viosapic_set_irq(d, irq, level); +} void viosapic_init(struct domain *d) { diff --git a/xen/arch/ia64/vmx/vmx_hypercall.c b/xen/arch/ia64/vmx/vmx_hypercall.c index e9acb6ec5d..08726390f4 100644 --- a/xen/arch/ia64/vmx/vmx_hypercall.c +++ b/xen/arch/ia64/vmx/vmx_hypercall.c @@ -37,6 +37,72 @@ #include #include +static int hvmop_set_isa_irq_level( + XEN_GUEST_HANDLE(xen_hvm_set_isa_irq_level_t) uop) +{ + struct xen_hvm_set_isa_irq_level op; + struct domain *d; + int rc; + + if ( copy_from_guest(&op, uop, 1) ) + return -EFAULT; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + if ( op.isa_irq > 15 ) + return -EINVAL; + + d = find_domain_by_id(op.domid); + if ( d == NULL ) + return -ESRCH; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto out; + + rc = 0; + viosapic_set_irq(d, op.isa_irq, op.level); + + out: + put_domain(d); + return rc; +} + +static int hvmop_set_pci_intx_level( + XEN_GUEST_HANDLE(xen_hvm_set_pci_intx_level_t) uop) +{ + struct xen_hvm_set_pci_intx_level op; + struct domain *d; + int rc; + + if ( copy_from_guest(&op, uop, 1) ) + return -EFAULT; + + if ( !IS_PRIV(current->domain) ) + return -EPERM; + + if ( (op.domain > 0) || (op.bus > 0) || (op.device > 31) || (op.intx > 3) ) + return -EINVAL; + + d = find_domain_by_id(op.domid); + if ( d == NULL ) + return -ESRCH; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto out; + + rc = 0; + viosapic_set_pci_irq(d, op.device, op.intx, op.level); + + out: + put_domain(d); + return rc; +} + + + long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) { @@ -80,30 +146,19 @@ do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg) break; } - case HVMOP_set_irq_level: - { - struct xen_hvm_set_irq_level op; - struct domain *d; - - if (copy_from_guest(&op, arg, 1)) - return -EFAULT; - - if (!IS_PRIV(current->domain)) - return -EPERM; - - d = find_domain_by_id(op.domid); - if (d == NULL) - return -ESRCH; - - rc = -EINVAL; - if (is_hvm_domain(d)) { - viosapic_set_irq(d, op.irq, op.level); - rc = 0; - } - - put_domain(d); + case HVMOP_set_pci_intx_level: + rc = hvmop_set_pci_intx_level( + guest_handle_cast(arg, xen_hvm_set_pci_intx_level_t)); + break; + + case HVMOP_set_isa_irq_level: + rc = hvmop_set_isa_irq_level( + guest_handle_cast(arg, xen_hvm_set_isa_irq_level_t)); + break; + + case HVMOP_set_pci_link_route: + rc = 0; break; - } default: gdprintk(XENLOG_INFO, "Bad HVM op %ld.\n", op); diff --git a/xen/include/asm-ia64/viosapic.h b/xen/include/asm-ia64/viosapic.h index 42b54e822c..4802279dce 100644 --- a/xen/include/asm-ia64/viosapic.h +++ b/xen/include/asm-ia64/viosapic.h @@ -42,7 +42,7 @@ #define VIOSAPIC_VERSION_ID 0x21 /* IOSAPIC version */ -#define VIOSAPIC_NUM_PINS 24 +#define VIOSAPIC_NUM_PINS 48 #define VIOSAPIC_DEFAULT_BASE_ADDRESS 0xfec00000 #define VIOSAPIC_MEM_LENGTH 0x100 @@ -74,19 +74,17 @@ union viosapic_rte }; struct viosapic { - uint32_t irr; - uint32_t irr_xen; /* interrupts forced on by the hypervisor. */ - uint32_t isr; /* This is used for level trigger */ - uint32_t imr; + uint64_t irr; + uint64_t isr; /* This is used for level trigger */ uint32_t ioregsel; spinlock_t lock; - unsigned long base_address; + uint64_t base_address; union viosapic_rte redirtbl[VIOSAPIC_NUM_PINS]; }; void viosapic_init(struct domain *d); -void viosapic_set_xen_irq(struct domain *d, int irq, int level); void viosapic_set_irq(struct domain *d, int irq, int level); +void viosapic_set_pci_irq(struct domain *d, int device, int intx, int level); void viosapic_write(struct vcpu *v, unsigned long addr, unsigned long length, unsigned long val); From 7169017f841ddc48438c25b58973405cfa328b44 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Sat, 2 Dec 2006 16:39:53 +0000 Subject: [PATCH 162/282] Make the xenfb tools an optional part of the build, as they introduce new dependencies (libvncserver and libsdl devel packages). Enable them with XENFB_TOOLS=y. Signed-off-by: Ewan Mellor --- Config.mk | 2 +- tools/Makefile | 2 +- tools/check/Makefile | 6 ++++-- tools/check/check_libvncserver | 6 ++++++ tools/check/check_sdl | 6 ++++++ 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Config.mk b/Config.mk index 364c7231c4..08873d69d4 100644 --- a/Config.mk +++ b/Config.mk @@ -69,8 +69,8 @@ ACM_DEFAULT_SECURITY_POLICY ?= ACM_NULL_POLICY # Optional components XENSTAT_XENTOP ?= y - VTPM_TOOLS ?= n LIBXENAPI_BINDINGS ?= n +XENFB_TOOLS ?= n -include $(XEN_ROOT)/.config diff --git a/tools/Makefile b/tools/Makefile index 29ce67dfe2..b4156fc904 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -19,7 +19,7 @@ SUBDIRS-y += xenstat SUBDIRS-y += libaio SUBDIRS-y += blktap SUBDIRS-y += libfsimage -SUBDIRS-y += xenfb +SUBDIRS-$(XENFB_TOOLS) += xenfb SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen # These don't cross-compile diff --git a/tools/check/Makefile b/tools/check/Makefile index 4605c03c39..0b87aea259 100644 --- a/tools/check/Makefile +++ b/tools/check/Makefile @@ -1,3 +1,5 @@ +XEN_ROOT = ../.. +include $(XEN_ROOT)/tools/Rules.mk .PHONY: all all: build @@ -5,7 +7,7 @@ all: build # Check this machine is OK for building on. .PHONY: build build: - ./chk build + XENFB_TOOLS=$(XENFB_TOOLS) ./chk build # Check this machine is OK for installing on. # DO NOT use this check from 'make install' in the parent @@ -13,7 +15,7 @@ build: # copy rather than actually installing. .PHONY: install install: - ./chk install + XENFB_TOOLS=$(XENFB_TOOLS) ./chk install .PHONY: clean clean: diff --git a/tools/check/check_libvncserver b/tools/check/check_libvncserver index dc9ed9153d..69efd063b3 100755 --- a/tools/check/check_libvncserver +++ b/tools/check/check_libvncserver @@ -1,6 +1,12 @@ #!/bin/sh # CHECK-BUILD CHECK-INSTALL +if [ ! "$XENFB_TOOLS" = "y" ] +then + echo -n "unused, " + exit 0 +fi + RC=0 LIBVNCSERVER_CONFIG="$(which libvncserver-config)" diff --git a/tools/check/check_sdl b/tools/check/check_sdl index 7832910355..aac0130fe3 100755 --- a/tools/check/check_sdl +++ b/tools/check/check_sdl @@ -1,6 +1,12 @@ #!/bin/sh # CHECK-BUILD CHECK-INSTALL +if [ ! "$XENFB_TOOLS" = "y" ] +then + echo -n "unused, " + exit 0 +fi + RC=0 SDL_CONFIG="$(which sdl-config)" From c293efbc1671e08aa16ace7be7944405a8d6efd9 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Sat, 2 Dec 2006 15:19:50 -0700 Subject: [PATCH 163/282] [IA64] update xc_set_hvm_param(), add xc_get_hvm_param() Signed-off-by: Alex Williamson --- tools/libxc/ia64/xc_ia64_hvm_build.c | 36 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_hvm_build.c b/tools/libxc/ia64/xc_ia64_hvm_build.c index c39542eb12..c12dfc3d84 100644 --- a/tools/libxc/ia64/xc_ia64_hvm_build.c +++ b/tools/libxc/ia64/xc_ia64_hvm_build.c @@ -41,7 +41,7 @@ error_out: return -1; } -static void +int xc_set_hvm_param(int handle, domid_t dom, int param, unsigned long value) { DECLARE_HYPERCALL; @@ -56,15 +56,37 @@ xc_set_hvm_param(int handle, domid_t dom, int param, unsigned long value) arg.index = param; arg.value = value; - if (mlock(&arg, sizeof(arg)) != 0) { - PERROR("Could not lock memory for set parameter"); - return; - } + if (mlock(&arg, sizeof(arg)) != 0) + return -1; rc = do_xen_hypercall(handle, &hypercall); safe_munlock(&arg, sizeof(arg)); - if (rc < 0) - PERROR("set HVM parameter failed (%d)", rc); + + return rc; +} + +int +xc_get_hvm_param(int handle, domid_t dom, int param, unsigned long *value) +{ + DECLARE_HYPERCALL; + xen_hvm_param_t arg; + int rc; + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_get_param; + hypercall.arg[1] = (unsigned long)&arg; + + arg.domid = dom; + arg.index = param; + + if (mlock(&arg, sizeof(arg)) != 0) + return -1; + + rc = do_xen_hypercall(handle, &hypercall); + safe_munlock(&arg, sizeof(arg)); + + *value = arg.value; + return rc; } #define HOB_SIGNATURE 0x3436474953424f48 // "HOBSIG64" From 43bbe5bc9680630a963f44acb54fc0128d581384 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Sun, 3 Dec 2006 13:30:23 +0000 Subject: [PATCH 164/282] Revert the change to destroy all VMs when skipping or failing tests -- this needs more thought, because people shouldn't need to set up their Xen-API server to run the non-Xen-API bits of the test, and at the moment, you get authentication failures on every SKIP. Signed-off-by: Ewan Mellor --- tools/xm-test/lib/XmTestLib/Test.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/xm-test/lib/XmTestLib/Test.py b/tools/xm-test/lib/XmTestLib/Test.py index 7efbc0f3e3..68a176c273 100644 --- a/tools/xm-test/lib/XmTestLib/Test.py +++ b/tools/xm-test/lib/XmTestLib/Test.py @@ -33,7 +33,6 @@ import select import signal import re import glob -import xapi TEST_PASS = 0 TEST_FAIL = 255 @@ -134,12 +133,10 @@ def becomeNonRoot(): def FAIL(format, *args): print "\nREASON:", (format % args) - xapi.vm_destroy_all() sys.exit(TEST_FAIL) def SKIP(format, *args): print "\nREASON:", (format % args) - xapi.vm_destroy_all() sys.exit(TEST_SKIP) def saveLog(logText, filename=None): From df69bc855199b6a79e8dcf31ad48e9534d59d109 Mon Sep 17 00:00:00 2001 From: "kaf24@localhost.localdomain" Date: Sun, 3 Dec 2006 17:15:48 +0000 Subject: [PATCH 165/282] [XEN] Add 'insn_fetch' memory operation to the x86_emulator. This can be used to perform correct access checks, provide appropriate error codes when injecting faults, and to implement an instruction-stream prefetch cache (which is included here for HVM PTE update emulations). Signed-off-by: Keir Fraser --- tools/tests/test_x86_emulator.c | 6 +- xen/arch/x86/mm.c | 9 +- xen/arch/x86/mm/shadow/common.c | 143 +++++++++++++++++++++++------- xen/arch/x86/mm/shadow/multi.c | 12 +-- xen/arch/x86/mm/shadow/private.h | 6 ++ xen/arch/x86/x86_emulate.c | 76 ++++++++-------- xen/include/asm-x86/x86_emulate.h | 14 ++- 7 files changed, 187 insertions(+), 79 deletions(-) diff --git a/tools/tests/test_x86_emulator.c b/tools/tests/test_x86_emulator.c index e22e342ce2..64797d3f81 100644 --- a/tools/tests/test_x86_emulator.c +++ b/tools/tests/test_x86_emulator.c @@ -88,7 +88,11 @@ static int cmpxchg8b( } static struct x86_emulate_ops emulops = { - read, write, cmpxchg, cmpxchg8b + .read = read, + .insn_fetch = read, + .write = write, + .cmpxchg = cmpxchg, + .cmpxchg8b = cmpxchg8b }; int main(int argc, char **argv) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 47fb500fc6..48dea7cffb 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -3224,10 +3224,11 @@ static int ptwr_emulated_cmpxchg8b( } static struct x86_emulate_ops ptwr_emulate_ops = { - .read = ptwr_emulated_read, - .write = ptwr_emulated_write, - .cmpxchg = ptwr_emulated_cmpxchg, - .cmpxchg8b = ptwr_emulated_cmpxchg8b + .read = ptwr_emulated_read, + .insn_fetch = ptwr_emulated_read, + .write = ptwr_emulated_write, + .cmpxchg = ptwr_emulated_cmpxchg, + .cmpxchg8b = ptwr_emulated_cmpxchg8b }; /* Write page fault handler: check if guest is trying to modify a PTE. */ diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 5b6965a7f1..a109716c9f 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -78,43 +78,54 @@ struct segment_register *hvm_get_seg_reg( return seg_reg; } +enum hvm_access_type { + hvm_access_insn_fetch, hvm_access_read, hvm_access_write +}; + static int hvm_translate_linear_addr( enum x86_segment seg, unsigned long offset, unsigned int bytes, - unsigned int is_write, + enum hvm_access_type access_type, struct sh_emulate_ctxt *sh_ctxt, unsigned long *paddr) { - struct segment_register *creg, *dreg; + struct segment_register *reg = hvm_get_seg_reg(seg, sh_ctxt); unsigned long limit, addr = offset; uint32_t last_byte; - creg = hvm_get_seg_reg(x86_seg_cs, sh_ctxt); - dreg = hvm_get_seg_reg(seg, sh_ctxt); - - if ( !creg->attr.fields.l || !hvm_long_mode_enabled(current) ) + if ( sh_ctxt->ctxt.mode != X86EMUL_MODE_PROT64 ) { /* * COMPATIBILITY MODE: Apply segment checks and add base. */ - /* If this is a store, is the segment a writable data segment? */ - if ( is_write && ((dreg->attr.fields.type & 0xa) != 0x2) ) - goto gpf; + switch ( access_type ) + { + case hvm_access_read: + if ( (reg->attr.fields.type & 0xa) == 0x8 ) + goto gpf; /* execute-only code segment */ + break; + case hvm_access_write: + if ( (reg->attr.fields.type & 0xa) != 0x2 ) + goto gpf; /* not a writable data segment */ + break; + default: + break; + } /* Calculate the segment limit, including granularity flag. */ - limit = dreg->limit; - if ( dreg->attr.fields.g ) + limit = reg->limit; + if ( reg->attr.fields.g ) limit = (limit << 12) | 0xfff; last_byte = offset + bytes - 1; /* Is this a grows-down data segment? Special limit check if so. */ - if ( (dreg->attr.fields.type & 0xc) == 0x4 ) + if ( (reg->attr.fields.type & 0xc) == 0x4 ) { /* Is upper limit 0xFFFF or 0xFFFFFFFF? */ - if ( !dreg->attr.fields.db ) + if ( !reg->attr.fields.db ) last_byte = (uint16_t)last_byte; /* Check first byte and last byte against respective bounds. */ @@ -128,7 +139,7 @@ static int hvm_translate_linear_addr( * Hardware truncates to 32 bits in compatibility mode. * It does not truncate to 16 bits in 16-bit address-size mode. */ - addr = (uint32_t)(addr + dreg->base); + addr = (uint32_t)(addr + reg->base); } else { @@ -137,7 +148,7 @@ static int hvm_translate_linear_addr( */ if ( (seg == x86_seg_fs) || (seg == x86_seg_gs) ) - addr += dreg->base; + addr += reg->base; if ( !is_canonical_address(addr) ) goto gpf; @@ -153,18 +164,18 @@ static int hvm_translate_linear_addr( } static int -sh_x86_emulate_read(enum x86_segment seg, - unsigned long offset, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) +hvm_read(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + enum hvm_access_type access_type, + struct sh_emulate_ctxt *sh_ctxt) { - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); unsigned long addr; int rc, errcode; - rc = hvm_translate_linear_addr(seg, offset, bytes, 0, sh_ctxt, &addr); + rc = hvm_translate_linear_addr( + seg, offset, bytes, access_type, sh_ctxt, &addr); if ( rc ) return rc; @@ -189,10 +200,78 @@ sh_x86_emulate_read(enum x86_segment seg, * of a write fault at the end of the instruction we're emulating. */ SHADOW_PRINTK("read failed to va %#lx\n", addr); errcode = ring_3(sh_ctxt->ctxt.regs) ? PFEC_user_mode : 0; + if ( access_type == hvm_access_insn_fetch ) + errcode |= PFEC_insn_fetch; hvm_inject_exception(TRAP_page_fault, errcode, addr + bytes - rc); return X86EMUL_PROPAGATE_FAULT; } +void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, + struct cpu_user_regs *regs) +{ + struct segment_register *creg; + struct vcpu *v = current; + unsigned long addr; + + sh_ctxt->ctxt.regs = regs; + + /* Segment cache initialisation. Primed with CS. */ + sh_ctxt->valid_seg_regs = 0; + creg = hvm_get_seg_reg(x86_seg_cs, sh_ctxt); + + /* Work out the emulation mode. */ + if ( hvm_long_mode_enabled(v) ) + sh_ctxt->ctxt.mode = creg->attr.fields.l ? + X86EMUL_MODE_PROT64 : X86EMUL_MODE_PROT32; + else if ( regs->eflags & X86_EFLAGS_VM ) + sh_ctxt->ctxt.mode = X86EMUL_MODE_REAL; + else + sh_ctxt->ctxt.mode = creg->attr.fields.db ? + X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16; + + /* Attempt to prefetch whole instruction. */ + sh_ctxt->insn_buf_bytes = + (!hvm_translate_linear_addr( + x86_seg_cs, regs->eip, sizeof(sh_ctxt->insn_buf), + hvm_access_insn_fetch, sh_ctxt, &addr) && + !hvm_copy_from_guest_virt( + sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf))) + ? sizeof(sh_ctxt->insn_buf) : 0; +} + +static int +sh_x86_emulate_read(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + return hvm_read(seg, offset, val, bytes, hvm_access_read, + container_of(ctxt, struct sh_emulate_ctxt, ctxt)); +} + +static int +sh_x86_emulate_insn_fetch(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + unsigned int insn_off = offset - ctxt->regs->eip; + + /* Fall back if requested bytes are not in the prefetch cache. */ + if ( unlikely((insn_off + bytes) > sh_ctxt->insn_buf_bytes) ) + return hvm_read(seg, offset, val, bytes, + hvm_access_insn_fetch, sh_ctxt); + + /* Hit the cache. Simple memcpy. */ + *val = 0; + memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes); + return X86EMUL_CONTINUE; +} + static int sh_x86_emulate_write(enum x86_segment seg, unsigned long offset, @@ -206,7 +285,8 @@ sh_x86_emulate_write(enum x86_segment seg, unsigned long addr; int rc; - rc = hvm_translate_linear_addr(seg, offset, bytes, 1, sh_ctxt, &addr); + rc = hvm_translate_linear_addr( + seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); if ( rc ) return rc; @@ -232,7 +312,8 @@ sh_x86_emulate_cmpxchg(enum x86_segment seg, unsigned long addr; int rc; - rc = hvm_translate_linear_addr(seg, offset, bytes, 1, sh_ctxt, &addr); + rc = hvm_translate_linear_addr( + seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); if ( rc ) return rc; @@ -259,7 +340,8 @@ sh_x86_emulate_cmpxchg8b(enum x86_segment seg, unsigned long addr; int rc; - rc = hvm_translate_linear_addr(seg, offset, 8, 1, sh_ctxt, &addr); + rc = hvm_translate_linear_addr( + seg, offset, 8, hvm_access_write, sh_ctxt, &addr); if ( rc ) return rc; @@ -274,10 +356,11 @@ sh_x86_emulate_cmpxchg8b(enum x86_segment seg, struct x86_emulate_ops shadow_emulator_ops = { - .read = sh_x86_emulate_read, - .write = sh_x86_emulate_write, - .cmpxchg = sh_x86_emulate_cmpxchg, - .cmpxchg8b = sh_x86_emulate_cmpxchg8b, + .read = sh_x86_emulate_read, + .insn_fetch = sh_x86_emulate_insn_fetch, + .write = sh_x86_emulate_write, + .cmpxchg = sh_x86_emulate_cmpxchg, + .cmpxchg8b = sh_x86_emulate_cmpxchg8b, }; /**************************************************************************/ diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index b3a0da43b0..98ff07ace4 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -2808,24 +2808,20 @@ static int sh_page_fault(struct vcpu *v, return EXCRET_fault_fixed; emulate: - if ( !is_hvm_domain(d) ) + if ( !is_hvm_domain(d) || !guest_mode(regs) ) goto not_a_shadow_fault; hvm_store_cpu_guest_regs(v, regs, NULL); - emul_ctxt.ctxt.regs = regs; - emul_ctxt.ctxt.mode = (is_hvm_domain(d) ? - hvm_guest_x86_mode(v) : X86EMUL_MODE_HOST); - emul_ctxt.valid_seg_regs = 0; - SHADOW_PRINTK("emulate: eip=%#lx\n", regs->eip); + shadow_init_emulation(&emul_ctxt, regs); + /* * We do not emulate user writes. Instead we use them as a hint that the * page is no longer a page table. This behaviour differs from native, but * it seems very unlikely that any OS grants user access to page tables. - * We also disallow guest PTE updates from within Xen. */ - if ( (regs->error_code & PFEC_user_mode) || !guest_mode(regs) || + if ( (regs->error_code & PFEC_user_mode) || x86_emulate_memop(&emul_ctxt.ctxt, &shadow_emulator_ops) ) { SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n", diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h index c2c52d8f6a..e5a5796548 100644 --- a/xen/arch/x86/mm/shadow/private.h +++ b/xen/arch/x86/mm/shadow/private.h @@ -513,11 +513,17 @@ static inline void sh_unpin(struct vcpu *v, mfn_t smfn) struct sh_emulate_ctxt { struct x86_emulate_ctxt ctxt; + /* Cache of up to 15 bytes of instruction. */ + uint8_t insn_buf[15]; + uint8_t insn_buf_bytes; + /* Cache of segment registers already gathered for this emulation. */ unsigned int valid_seg_regs; struct segment_register seg_reg[6]; }; +void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, + struct cpu_user_regs *regs); #endif /* _XEN_SHADOW_PRIVATE_H */ diff --git a/xen/arch/x86/x86_emulate.c b/xen/arch/x86/x86_emulate.c index 1582bdf299..4f882556c4 100644 --- a/xen/arch/x86/x86_emulate.c +++ b/xen/arch/x86/x86_emulate.c @@ -19,11 +19,6 @@ #endif #include -#ifndef PFEC_write_access -#define PFEC_write_access (1U<<1) -#define PFEC_insn_fetch (1U<<4) -#endif - /* * Opcode effective-address decode tables. * Note that we only emulate instructions that have at least one memory @@ -374,15 +369,15 @@ do{ __asm__ __volatile__ ( \ #endif /* __i386__ */ /* Fetch next part of the instruction being emulated. */ -#define _insn_fetch(_size) \ -({ unsigned long _x; \ - rc = ops->read(x86_seg_cs, _regs.eip, &_x, (_size), ctxt); \ - if ( rc != 0 ) \ - goto done; \ - _regs.eip += (_size); \ - _x; \ +#define insn_fetch_bytes(_size) \ +({ unsigned long _x; \ + rc = ops->insn_fetch(x86_seg_cs, _regs.eip, &_x, (_size), ctxt); \ + if ( rc != 0 ) \ + goto done; \ + _regs.eip += (_size); \ + _x; \ }) -#define insn_fetch(_type) ((_type)_insn_fetch(sizeof(_type))) +#define insn_fetch_type(_type) ((_type)insn_fetch_bytes(sizeof(_type))) #define truncate_ea(ea) \ ({ unsigned long __ea = (ea); \ @@ -481,7 +476,7 @@ x86_emulate_memop( /* Legacy prefixes. */ for ( i = 0; i < 8; i++ ) { - switch ( b = insn_fetch(uint8_t) ) + switch ( b = insn_fetch_type(uint8_t) ) { case 0x66: /* operand-size override */ op_bytes ^= 6; /* switch between 2/4 bytes */ @@ -530,7 +525,7 @@ x86_emulate_memop( rex_prefix = b; if ( b & 8 ) /* REX.W */ op_bytes = 8; - b = insn_fetch(uint8_t); + b = insn_fetch_type(uint8_t); } /* Opcode byte(s). */ @@ -541,7 +536,7 @@ x86_emulate_memop( if ( b == 0x0f ) { twobyte = 1; - b = insn_fetch(uint8_t); + b = insn_fetch_type(uint8_t); d = twobyte_table[b]; } @@ -553,7 +548,7 @@ x86_emulate_memop( /* ModRM and SIB bytes. */ if ( d & ModRM ) { - modrm = insn_fetch(uint8_t); + modrm = insn_fetch_type(uint8_t); modrm_mod = (modrm & 0xc0) >> 6; modrm_reg = ((rex_prefix & 4) << 1) | ((modrm & 0x38) >> 3); modrm_rm = modrm & 0x07; @@ -577,9 +572,16 @@ x86_emulate_memop( } switch ( modrm_mod ) { - case 0: if ( modrm_rm == 6 ) ea_off = insn_fetch(int16_t); break; - case 1: ea_off += insn_fetch(int8_t); break; - case 2: ea_off += insn_fetch(int16_t); break; + case 0: + if ( modrm_rm == 6 ) + ea_off = insn_fetch_type(int16_t); + break; + case 1: + ea_off += insn_fetch_type(int8_t); + break; + case 2: + ea_off += insn_fetch_type(int16_t); + break; } } else @@ -587,14 +589,14 @@ x86_emulate_memop( /* 32/64-bit ModR/M decode. */ if ( modrm_rm == 4 ) { - sib = insn_fetch(uint8_t); + sib = insn_fetch_type(uint8_t); sib_index = ((sib >> 3) & 7) | ((rex_prefix << 2) & 8); sib_base = (sib & 7) | ((rex_prefix << 3) & 8); if ( sib_index != 4 ) ea_off = *(long *)decode_register(sib_index, &_regs, 0); ea_off <<= (sib >> 6) & 3; if ( (modrm_mod == 0) && ((sib_base & 7) == 5) ) - ea_off += insn_fetch(int32_t); + ea_off += insn_fetch_type(int32_t); else ea_off += *(long *)decode_register(sib_base, &_regs, 0); } @@ -608,7 +610,7 @@ x86_emulate_memop( case 0: if ( (modrm_rm & 7) != 5 ) break; - ea_off = insn_fetch(int32_t); + ea_off = insn_fetch_type(int32_t); if ( mode != X86EMUL_MODE_PROT64 ) break; /* Relative to RIP of next instruction. Argh! */ @@ -624,8 +626,12 @@ x86_emulate_memop( ea_off += (d & ByteOp) ? 1 : ((op_bytes == 8) ? 4 : op_bytes); break; - case 1: ea_off += insn_fetch(int8_t); break; - case 2: ea_off += insn_fetch(int32_t); break; + case 1: + ea_off += insn_fetch_type(int8_t); + break; + case 2: + ea_off += insn_fetch_type(int32_t); + break; } } @@ -684,15 +690,15 @@ x86_emulate_memop( /* NB. Immediates are sign-extended as necessary. */ switch ( src.bytes ) { - case 1: src.val = insn_fetch(int8_t); break; - case 2: src.val = insn_fetch(int16_t); break; - case 4: src.val = insn_fetch(int32_t); break; + case 1: src.val = insn_fetch_type(int8_t); break; + case 2: src.val = insn_fetch_type(int16_t); break; + case 4: src.val = insn_fetch_type(int32_t); break; } break; case SrcImmByte: src.type = OP_IMM; src.bytes = 1; - src.val = insn_fetch(int8_t); + src.val = insn_fetch_type(int8_t); break; } @@ -885,9 +891,9 @@ x86_emulate_memop( if ( src.bytes == 8 ) src.bytes = 4; switch ( src.bytes ) { - case 1: src.val = insn_fetch(int8_t); break; - case 2: src.val = insn_fetch(int16_t); break; - case 4: src.val = insn_fetch(int32_t); break; + case 1: src.val = insn_fetch_type(int8_t); break; + case 2: src.val = insn_fetch_type(int16_t); break; + case 4: src.val = insn_fetch_type(int32_t); break; } goto test; case 2: /* not */ @@ -986,7 +992,7 @@ x86_emulate_memop( dst.type = OP_REG; dst.reg = (unsigned long *)&_regs.eax; dst.bytes = (d & ByteOp) ? 1 : op_bytes; - if ( (rc = ops->read(ea_seg, _insn_fetch(ad_bytes), + if ( (rc = ops->read(ea_seg, insn_fetch_bytes(ad_bytes), &dst.val, dst.bytes, ctxt)) != 0 ) goto done; break; @@ -994,7 +1000,7 @@ x86_emulate_memop( /* Destination EA is not encoded via ModRM. */ dst.type = OP_MEM; dst.mem_seg = ea_seg; - dst.mem_off = _insn_fetch(ad_bytes); + dst.mem_off = insn_fetch_bytes(ad_bytes); dst.bytes = (d & ByteOp) ? 1 : op_bytes; dst.val = (unsigned long)_regs.eax; break; @@ -1198,7 +1204,7 @@ x86_emulate_memop( for ( ea_off = ctxt->regs->eip; ea_off < _regs.eip; ea_off++ ) { unsigned long x; - ops->read(x86_seg_cs, ea_off, &x, 1, ctxt); + ops->insn_fetch(x86_seg_cs, ea_off, &x, 1, ctxt); printk(" %02x", (uint8_t)x); } printk("\n"); diff --git a/xen/include/asm-x86/x86_emulate.h b/xen/include/asm-x86/x86_emulate.h index ef23291cdc..89a42da7b0 100644 --- a/xen/include/asm-x86/x86_emulate.h +++ b/xen/include/asm-x86/x86_emulate.h @@ -56,7 +56,8 @@ struct x86_emulate_ops /* * All functions: * @seg: [IN ] Segment being dereferenced (specified as x86_seg_??). - * @offset [IN ] Offset within segment. + * @offset:[IN ] Offset within segment. + * @ctxt: [IN ] Emulation context info as passed to the emulator. */ /* @@ -71,6 +72,17 @@ struct x86_emulate_ops unsigned int bytes, struct x86_emulate_ctxt *ctxt); + /* + * insn_fetch: Emulate fetch from instruction byte stream. + * Parameters are same as for 'read'. @seg is always x86_seg_cs. + */ + int (*insn_fetch)( + enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt); + /* * write: Emulate a memory write. * @val: [IN ] Value to write to memory (low-order bytes used as req'd). From 0831896293f7f24b0e7acdbb250a8b10751491ba Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 3 Dec 2006 17:44:14 +0000 Subject: [PATCH 166/282] [XEN] Fix 32-bit build. Signed-off-by: Keir Fraser --- xen/include/asm-x86/hvm/hvm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 20373b0ec9..13ee040fdb 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -165,7 +165,7 @@ hvm_long_mode_enabled(struct vcpu *v) return hvm_funcs.long_mode_enabled(v); } #else -#define hvm_long_mode_enabled(v) 0 +#define hvm_long_mode_enabled(v) (v,0) #endif static inline int From 6b995a3b55f8d6660985958a141609f251b82d9e Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 4 Dec 2006 09:08:47 +0000 Subject: [PATCH 167/282] [PATCH 01/02] Kexec / Kdump: Use NOTE_ALIGN() instead of ALIGN() ALIGN() is already defined in xen/include/asm-ia64/config.h. This patch renames ALIGN() to NOTE_ALIGN() to make the kexec code build on ia64. Signed-Off-By: Magnus Damm --- xen/include/xen/elfcore.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/include/xen/elfcore.h b/xen/include/xen/elfcore.h index d578d0dd0b..75ce7c49ef 100644 --- a/xen/include/xen/elfcore.h +++ b/xen/include/xen/elfcore.h @@ -71,8 +71,8 @@ typedef struct * That requires infrastructure. Let's not. */ -#define ALIGN(x, n) ((x + ((1 << n) - 1)) / (1 << n)) -#define PAD32(x) u32 pad_data[ALIGN(x, 2)] +#define NOTE_ALIGN(x, n) ((x + ((1 << n) - 1)) / (1 << n)) +#define PAD32(x) u32 pad_data[NOTE_ALIGN(x, 2)] #define TYPEDEF_NOTE(type, strlen, desctype) \ typedef struct { \ From f5bdee9abde46ffff04e9273ba8cbfe4f4a493c7 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 4 Dec 2006 09:08:47 +0000 Subject: [PATCH 168/282] [PATCH 02/02] Kexec / Kdump: Don't declare _end _end is already declared in xen/include/asm/config.h, so don't declare it twice. This solves a powerpc/ia64 build problem where _end is declared as char _end[] compared to unsigned long _end on x86. Signed-Off-By: Magnus Damm --- xen/common/kexec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/common/kexec.c b/xen/common/kexec.c index f3f5f01731..2f8b8e0de3 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -158,7 +158,7 @@ static int kexec_get_reserve(xen_kexec_range_t *range) return 0; } -extern unsigned long _text, _end; +extern unsigned long _text; static int kexec_get_xen(xen_kexec_range_t *range, int get_ma) { @@ -167,7 +167,7 @@ static int kexec_get_xen(xen_kexec_range_t *range, int get_ma) else range->start = (unsigned long) &_text; - range->size = &_end - &_text; + range->size = (unsigned long)&_end - (unsigned long)&_text; return 0; } From b3fba4e07b25e60247b408bb7420d558fbe42b69 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 4 Dec 2006 09:20:12 +0000 Subject: [PATCH 169/282] Remove useless segments push/pop in VMXAssist. According to Intel Spec, segments registors are cleared when exiting virtual-8086 mode through trap or interrupts gate, so it's no need to save their values in stack. Signed-off-by: Xin Li --- tools/firmware/vmxassist/setup.c | 22 +++++++++++----------- tools/firmware/vmxassist/trap.S | 16 ++-------------- tools/firmware/vmxassist/util.c | 6 ++---- tools/firmware/vmxassist/vm86.c | 21 +++++++-------------- tools/firmware/vmxassist/vm86.h | 2 -- 5 files changed, 22 insertions(+), 45 deletions(-) diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c index 4f82ca0d9e..d1c47b2325 100644 --- a/tools/firmware/vmxassist/setup.c +++ b/tools/firmware/vmxassist/setup.c @@ -66,7 +66,7 @@ struct vmx_assist_context newctx; unsigned long memory_size; int initialize_real_mode; -extern char stack[], stack_top[]; +extern char stack_top[]; extern unsigned trap_handlers[]; void @@ -201,7 +201,7 @@ void enter_real_mode(struct regs *regs) { /* mask off TSS busy bit */ - gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL; + gdt[TSS_SELECTOR / sizeof(gdt[0])] &= ~0x0000020000000000ULL; /* start 8086 emulation of BIOS */ if (initialize_real_mode) { @@ -219,8 +219,10 @@ enter_real_mode(struct regs *regs) regs->cs = booting_vector << 8; /* AP entry point */ regs->eip = 0; } - regs->uesp = 0; - regs->uss = 0; + + regs->uesp = regs->uss = 0; + regs->eax = regs->ecx = regs->edx = regs->ebx = 0; + regs->esp = regs->ebp = regs->esi = regs->edi = 0; /* intercept accesses to the PIC */ setiomap(PIC_MASTER+PIC_CMD); @@ -236,14 +238,12 @@ enter_real_mode(struct regs *regs) /* this should get us into 16-bit mode */ return; - } else { - /* go from protected to real mode */ - regs->eflags |= EFLAGS_VM; - - set_mode(regs, VM86_PROTECTED_TO_REAL); - - emulate(regs); } + + /* go from protected to real mode */ + regs->eflags |= EFLAGS_VM; + set_mode(regs, VM86_PROTECTED_TO_REAL); + emulate(regs); } /* diff --git a/tools/firmware/vmxassist/trap.S b/tools/firmware/vmxassist/trap.S index 30e87adb85..d5ece3e143 100644 --- a/tools/firmware/vmxassist/trap.S +++ b/tools/firmware/vmxassist/trap.S @@ -100,10 +100,6 @@ trap_handlers: .code32 .align 16 common_trap: /* common trap handler */ - pushl %gs - pushl %fs - pushl %ds - pushl %es pushal movl $(DATA_SELECTOR), %eax /* make sure these are sane */ @@ -114,17 +110,13 @@ common_trap: /* common trap handler */ movl %esp, %ebp pushl %ebp - pushl 52(%ebp) - pushl 48(%ebp) + pushl 36(%ebp) + pushl 32(%ebp) call trap /* trap(trapno, errno, regs) */ addl $12, %esp trap_return: popal - popl %es - popl %ds - popl %fs - popl %gs addl $8, %esp /* skip trapno, errno */ iret /* NOT REACHED */ @@ -152,10 +144,6 @@ switch_to_real_mode: pushl oldctx+VMX_ASSIST_CTX_EIP pushl $-1 /* trapno, errno */ pushl $-1 - pushl %gs - pushl %fs - pushl %ds - pushl %es pushal movl %esp, %ebp diff --git a/tools/firmware/vmxassist/util.c b/tools/firmware/vmxassist/util.c index 6ae4b25f79..2c4c016989 100644 --- a/tools/firmware/vmxassist/util.c +++ b/tools/firmware/vmxassist/util.c @@ -62,17 +62,15 @@ dump_regs(struct regs *regs) regs->eax, regs->ecx, regs->edx, regs->ebx); printf("esp %8x ebp %8x esi %8x edi %8x\n", regs->esp, regs->ebp, regs->esi, regs->edi); - printf("es %8x ds %8x fs %8x gs %8x\n", - regs->es, regs->ds, regs->fs, regs->gs); printf("trapno %8x errno %8x\n", regs->trapno, regs->errno); printf("eip %8x cs %8x eflags %8x\n", regs->eip, regs->cs, regs->eflags); - printf("uesp %8x uss %8x \n", + printf("uesp %8x uss %8x\n", regs->uesp, regs->uss); printf("ves %8x vds %8x vfs %8x vgs %8x\n", regs->ves, regs->vds, regs->vfs, regs->vgs); - printf("cr0 %8lx cr2 %8x cr3 %8lx cr4 %8lx\n", + printf("cr0 %8lx cr2 %8x cr3 %8lx cr4 %8lx\n\n", (long)oldctx.cr0, get_cr2(), (long)oldctx.cr3, (long)oldctx.cr4); } diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c index 5bae53ed6d..7e37de63b8 100644 --- a/tools/firmware/vmxassist/vm86.c +++ b/tools/firmware/vmxassist/vm86.c @@ -376,9 +376,9 @@ segment(unsigned prefix, struct regs *regs, unsigned seg) if (prefix & SEG_SS) seg = regs->uss; if (prefix & SEG_FS) - seg = regs->fs; + seg = regs->vfs; if (prefix & SEG_GS) - seg = regs->gs; + seg = regs->vgs; return seg; } @@ -934,6 +934,8 @@ load_or_clear_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs static void protected_mode(struct regs *regs) { + extern char stack_top[]; + regs->eflags &= ~(EFLAGS_TF|EFLAGS_VM); oldctx.eip = regs->eip; @@ -958,12 +960,10 @@ protected_mode(struct regs *regs) &oldctx.gs_limit, &oldctx.gs_arbytes); /* initialize jump environment to warp back to protected mode */ + regs->uss = DATA_SELECTOR; + regs->uesp = stack_top; regs->cs = CODE_SELECTOR; - regs->ds = DATA_SELECTOR; - regs->es = DATA_SELECTOR; - regs->fs = DATA_SELECTOR; - regs->gs = DATA_SELECTOR; - regs->eip = (unsigned) &switch_to_protected_mode; + regs->eip = (unsigned) switch_to_protected_mode; /* this should get us into 32-bit mode */ } @@ -975,10 +975,6 @@ static void real_mode(struct regs *regs) { regs->eflags |= EFLAGS_VM | 0x02; - regs->ds = DATA_SELECTOR; - regs->es = DATA_SELECTOR; - regs->fs = DATA_SELECTOR; - regs->gs = DATA_SELECTOR; /* * When we transition from protected to real-mode and we @@ -1070,9 +1066,6 @@ set_mode(struct regs *regs, enum vm86_mode newmode) case VM86_PROTECTED: if (mode == VM86_REAL_TO_PROTECTED) { protected_mode(regs); -// printf("\n"); - mode = newmode; - return; } else panic("unexpected protected mode transition"); break; diff --git a/tools/firmware/vmxassist/vm86.h b/tools/firmware/vmxassist/vm86.h index 4c6609daf0..ea8c2728d3 100644 --- a/tools/firmware/vmxassist/vm86.h +++ b/tools/firmware/vmxassist/vm86.h @@ -34,7 +34,6 @@ struct regs { unsigned edi, esi, ebp, esp, ebx, edx, ecx, eax; - unsigned es, ds, fs, gs; unsigned trapno, errno; unsigned eip, cs, eflags, uesp, uss; unsigned ves, vds, vfs, vgs; @@ -55,7 +54,6 @@ enum vm86_mode { extern enum vm86_mode prevmode, mode; extern struct vmx_assist_context oldctx; -extern struct vmx_assist_context newctx; extern void emulate(struct regs *); extern void dump_regs(struct regs *); From 00f75a257f970be28fce18fcea14dc124fd73540 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 4 Dec 2006 09:21:10 +0000 Subject: [PATCH 170/282] Add XEN_FRAMEBUFFER to -xen defconfigs. Signed-off-by: Atsushi SAKAI --- buildconfigs/linux-defconfig_xen_ia64 | 2 ++ buildconfigs/linux-defconfig_xen_x86_32 | 2 ++ buildconfigs/linux-defconfig_xen_x86_64 | 2 ++ 3 files changed, 6 insertions(+) diff --git a/buildconfigs/linux-defconfig_xen_ia64 b/buildconfigs/linux-defconfig_xen_ia64 index 1bdc8edb4c..e04b1db69f 100644 --- a/buildconfigs/linux-defconfig_xen_ia64 +++ b/buildconfigs/linux-defconfig_xen_ia64 @@ -1548,6 +1548,8 @@ CONFIG_XEN_PCIDEV_BACKEND_SLOT=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_FRAMEBUFFER=y +CONFIG_XEN_KEYBOARD=y # CONFIG_XEN_SCRUB_PAGES is not set CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/buildconfigs/linux-defconfig_xen_x86_32 b/buildconfigs/linux-defconfig_xen_x86_32 index 6128a1012b..993da59152 100644 --- a/buildconfigs/linux-defconfig_xen_x86_32 +++ b/buildconfigs/linux-defconfig_xen_x86_32 @@ -3034,6 +3034,8 @@ CONFIG_XEN_NETDEV_LOOPBACK=y # CONFIG_XEN_TPMDEV_BACKEND is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_FRAMEBUFFER=y +CONFIG_XEN_KEYBOARD=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y diff --git a/buildconfigs/linux-defconfig_xen_x86_64 b/buildconfigs/linux-defconfig_xen_x86_64 index 0bca78b24f..ebee7ab056 100644 --- a/buildconfigs/linux-defconfig_xen_x86_64 +++ b/buildconfigs/linux-defconfig_xen_x86_64 @@ -2866,6 +2866,8 @@ CONFIG_XEN_TPMDEV_BACKEND=m # CONFIG_XEN_TPMDEV_CLOSE_IF_VTPM_FAILS is not set CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y +CONFIG_XEN_FRAMEBUFFER=y +CONFIG_XEN_KEYBOARD=y CONFIG_XEN_SCRUB_PAGES=y CONFIG_XEN_DISABLE_SERIAL=y CONFIG_XEN_SYSFS=y From a52cacaef95c4d42492298af9fb5281e6939e55c Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 4 Dec 2006 09:29:26 +0000 Subject: [PATCH 171/282] [QEMU] Error reporting in IDE device model. Following on from my patch to make blktap report I/O errors back to guest OS, a similar problem exists in the QEMU codebase. The IDE driver never reports I/O errors during read/write operations back to the guest OS. Instead all I/O operations are reported as succesfull. If, for example, the host FS holding the disk image fills up, then writes may fail due to lack of space. Since the guest OS never sees these failures, it assumes all is well & will continue writing. Eventually this can lead to severe & unrecoverable filesystem corruption. The attached patch fixes QEMU ide driver such that any failure of a read or write operation sets the appropriate IDE status/error registers. Having read the ATA-6 spec I think the most compliant behaviour is to set the status register to 'READY_STAT | ERR_STAT', and the error register to ABRT_ERR. There is already a convenience function ide_abort_command() in the QEMU codebase which does just this, so the attached patch simply calls that function. With this patch the guest OS sees the I/O failure & the kernel logs IDE errors and then retries the operation. This at least ensures that the guest can be shutdown the out of space issue in the host corrected and the guest restarted, without any serious filesystem damage having occurred. From: Daniel Berrange Signed-off-by: Keir Fraser --- tools/ioemu/hw/ide.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/tools/ioemu/hw/ide.c b/tools/ioemu/hw/ide.c index 94d5beaad5..532afbbffd 100644 --- a/tools/ioemu/hw/ide.c +++ b/tools/ioemu/hw/ide.c @@ -680,7 +680,7 @@ static void ide_set_sector(IDEState *s, int64_t sector_num) static void ide_sector_read(IDEState *s) { int64_t sector_num; - int ret, n; + int n; s->status = READY_STAT | SEEK_STAT; s->error = 0; /* not needed by IDE spec, but needed by Windows */ @@ -695,7 +695,11 @@ static void ide_sector_read(IDEState *s) #endif if (n > s->req_nb_sectors) n = s->req_nb_sectors; - ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); + if (bdrv_read(s->bs, sector_num, s->io_buffer, n) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return; + } ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); ide_set_irq(s); ide_set_sector(s, sector_num + n); @@ -721,7 +725,11 @@ static int ide_read_dma_cb(IDEState *s, if (n > MAX_MULT_SECTORS) n = MAX_MULT_SECTORS; sector_num = ide_get_sector(s); - bdrv_read(s->bs, sector_num, s->io_buffer, n); + if (bdrv_read(s->bs, sector_num, s->io_buffer, n) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return 0; + } s->io_buffer_index = 0; s->io_buffer_size = n * 512; len = s->io_buffer_size; @@ -767,7 +775,7 @@ static void ide_sector_write_timer_cb(void *opaque) static void ide_sector_write(IDEState *s) { int64_t sector_num; - int ret, n, n1; + int n, n1; s->status = READY_STAT | SEEK_STAT; sector_num = ide_get_sector(s); @@ -777,7 +785,11 @@ static void ide_sector_write(IDEState *s) n = s->nsector; if (n > s->req_nb_sectors) n = s->req_nb_sectors; - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); + if (bdrv_write(s->bs, sector_num, s->io_buffer, n) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return; + } s->nsector -= n; if (s->nsector == 0) { /* no more sector to write */ @@ -823,8 +835,13 @@ static int ide_write_dma_cb(IDEState *s, if (len == 0) { n = s->io_buffer_size >> 9; sector_num = ide_get_sector(s); - bdrv_write(s->bs, sector_num, s->io_buffer, - s->io_buffer_size >> 9); + if (bdrv_write(s->bs, sector_num, s->io_buffer, + s->io_buffer_size >> 9) != 0) { + ide_abort_command(s); + ide_set_irq(s); + return 0; + } + sector_num += n; ide_set_sector(s, sector_num); s->nsector -= n; From 78bc404b6b298e69910b4eefcad0aa50595d6023 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 10:20:56 +0000 Subject: [PATCH 172/282] With PERMISSIVE turned on, diagnose missing Enums and Bools, and improve the diagnosis of missing structure values. Signed-off-by: Ewan Mellor --- tools/libxen/src/xen_common.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tools/libxen/src/xen_common.c b/tools/libxen/src/xen_common.c index 50b8e377e0..ea0909d1a4 100644 --- a/tools/libxen/src/xen_common.c +++ b/tools/libxen/src/xen_common.c @@ -518,8 +518,14 @@ static void parse_into(xen_session *s, xmlNode *value_node, xmlChar *string = string_from_value(value_node, "string"); if (string == NULL) { +#if PERMISSIVE + fprintf(stderr, + "Expected an Enum from the server, but didn't get one\n"); + ((int *)value)[slot] = 0; +#else server_error( s, "Expected an Enum from the server, but didn't get one"); +#endif } else { @@ -567,8 +573,14 @@ static void parse_into(xen_session *s, xmlNode *value_node, xmlChar *string = string_from_value(value_node, "boolean"); if (string == NULL) { +#if PERMISSIVE + fprintf(stderr, + "Expected a Bool from the server, but didn't get one\n"); + ((bool *)value)[slot] = false; +#else server_error( s, "Expected a Bool from the server, but didn't get one"); +#endif } else { @@ -764,7 +776,6 @@ static void parse_into(xen_session *s, xmlNode *value_node, cur = cur->next; } -#if !PERMISSIVE /* Check that we've filled all fields. */ for (size_t i = 0; i < member_count; i++) { @@ -781,15 +792,20 @@ static void parse_into(xen_session *s, xmlNode *value_node, if (j == seen_count) { +#if PERMISSIVE + fprintf(stderr, + "Struct did not contain expected field %s.\n", + mem->key); +#else server_error_2(s, "Struct did not contain expected field", mem->key); free(result); free(checklist); return; +#endif } } -#endif free(checklist); ((void **)value)[slot] = result; From 3dca64847830af9a0a3bd74cdc869b6f2e402523 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 10:24:54 +0000 Subject: [PATCH 173/282] More capitalisation fixes. Signed-off-by: Ewan Mellor --- tools/libxen/src/xen_vm.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/libxen/src/xen_vm.c b/tools/libxen/src/xen_vm.c index aac8d4006d..9743222c02 100644 --- a/tools/libxen/src/xen_vm.c +++ b/tools/libxen/src/xen_vm.c @@ -85,28 +85,28 @@ static const struct_member xen_vm_record_struct_members[] = { .key = "memory_static_min", .type = &abstract_type_int, .offset = offsetof(xen_vm_record, memory_static_min) }, - { .key = "vcpus_policy", + { .key = "VCPUs_policy", .type = &abstract_type_string, .offset = offsetof(xen_vm_record, vcpus_policy) }, - { .key = "vcpus_params", + { .key = "VCPUs_params", .type = &abstract_type_string, .offset = offsetof(xen_vm_record, vcpus_params) }, - { .key = "vcpus_number", + { .key = "VCPUs_number", .type = &abstract_type_int, .offset = offsetof(xen_vm_record, vcpus_number) }, - { .key = "vcpus_utilisation", + { .key = "VCPUs_utilisation", .type = &abstract_type_int_float_map, .offset = offsetof(xen_vm_record, vcpus_utilisation) }, - { .key = "vcpus_features_required", + { .key = "VCPUs_features_required", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_required) }, - { .key = "vcpus_features_can_use", + { .key = "VCPUs_features_can_use", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_can_use) }, - { .key = "vcpus_features_force_on", + { .key = "VCPUs_features_force_on", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_force_on) }, - { .key = "vcpus_features_force_off", + { .key = "VCPUs_features_force_off", .type = &xen_cpu_feature_set_abstract_type_, .offset = offsetof(xen_vm_record, vcpus_features_force_off) }, { .key = "actions_after_shutdown", @@ -1124,7 +1124,7 @@ xen_vm_set_vcpus_policy(xen_session *session, xen_vm vm, char *policy) .u.string_val = policy } }; - xen_call_(session, "VM.set_vcpus_policy", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_policy", param_values, 2, NULL, NULL); return session->ok; } @@ -1140,7 +1140,7 @@ xen_vm_set_vcpus_params(xen_session *session, xen_vm vm, char *params) .u.string_val = params } }; - xen_call_(session, "VM.set_vcpus_params", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_params", param_values, 2, NULL, NULL); return session->ok; } @@ -1156,7 +1156,7 @@ xen_vm_set_vcpus_features_force_on(xen_session *session, xen_vm vm, struct xen_c .u.set_val = (arbitrary_set *)force_on } }; - xen_call_(session, "VM.set_vcpus_features_force_on", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_features_force_on", param_values, 2, NULL, NULL); return session->ok; } @@ -1172,7 +1172,7 @@ xen_vm_set_vcpus_features_force_off(xen_session *session, xen_vm vm, struct xen_ .u.set_val = (arbitrary_set *)force_off } }; - xen_call_(session, "VM.set_vcpus_features_force_off", param_values, 2, NULL, NULL); + xen_call_(session, "VM.set_VCPUs_features_force_off", param_values, 2, NULL, NULL); return session->ok; } From aeb915bbac8121ff17bafe8946b72247a73d1349 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 10:27:23 +0000 Subject: [PATCH 174/282] Tidy error message. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomainInfo.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 0aa71fc4e6..5488b17f8f 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1709,8 +1709,10 @@ class XendDomainInfo: dom = XendDomain.instance().domain_lookup_nr(name) if dom and dom.info['uuid'] != self.info['uuid']: - raise VmError("VM name '%s' already exists as domain %s" % - (name, str(dom.domid))) + raise VmError("VM name '%s' already exists%s" % + (name, + dom.domid is not None and + ("as domain %s" % str(dom.domid)) or "")) def update(self, info = None, refresh = True): From d529c3d93bb3e11d25c0d20d1aea5c97cfb1dcf6 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 13:37:53 +0000 Subject: [PATCH 175/282] Added rudimentary "xend reload" functionality. This allows you to reconfigure the services offered by Xend, without restarting the daemon itself. Signed-off-by: Ewan Mellor --- tools/examples/init.d/xend | 5 +- tools/misc/xend | 4 +- tools/python/xen/xend/server/SrvDaemon.py | 8 ++ tools/python/xen/xend/server/SrvServer.py | 119 +++++++++++++--------- 4 files changed, 86 insertions(+), 50 deletions(-) diff --git a/tools/examples/init.d/xend b/tools/examples/init.d/xend index 8ad407637c..c12b1a0386 100755 --- a/tools/examples/init.d/xend +++ b/tools/examples/init.d/xend @@ -36,7 +36,10 @@ case "$1" in status) xend status ;; - restart|reload|force-reload) + reload) + xend reload + ;; + restart|force-reload) xend restart await_daemons_up ;; diff --git a/tools/misc/xend b/tools/misc/xend index b0ee27f556..c35fbf00e0 100644 --- a/tools/misc/xend +++ b/tools/misc/xend @@ -109,7 +109,7 @@ def main(): daemon = SrvDaemon.instance() if not sys.argv[1:]: - print 'usage: %s {start|stop|restart}' % sys.argv[0] + print 'usage: %s {start|stop|reload|restart}' % sys.argv[0] elif sys.argv[1] == 'start': if os.uname()[0] != "SunOS": start_xenstored() @@ -123,6 +123,8 @@ def main(): return daemon.start(trace=1) elif sys.argv[1] == 'stop': return daemon.stop() + elif sys.argv[1] == 'reload': + return daemon.reloadConfig() elif sys.argv[1] == 'restart': start_xenstored() start_consoled() diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 35c64869d4..155062a704 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -60,6 +60,14 @@ class Daemon: return running + def reloadConfig(self): + """ + """ + pid = read_pid(XEND_PID_FILE) + if find_process(pid, XEND_PROCESS_NAME): + os.kill(pid, signal.SIGHUP) + + def status(self): """Returns the status of the xend daemon. The return value is defined by the LSB: diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index f995a13bf9..1b0ed9c0db 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -65,6 +65,7 @@ class XendServers: def __init__(self): self.servers = [] self.cleaningUp = False + self.reloadingConfig = False def add(self, server): self.servers.append(server) @@ -78,6 +79,11 @@ class XendServers: except: pass + def reloadConfig(self, signum = 0, frame = None): + log.debug("SrvServer.reloadConfig()") + self.reloadingConfig = True + self.cleanup(signum, frame) + def start(self, status): # Running the network script will spawn another process, which takes # the status fd with it unless we set FD_CLOEXEC. Failing to do this @@ -86,61 +92,71 @@ class XendServers: fcntl.fcntl(status, fcntl.F_SETFD, fcntl.FD_CLOEXEC) Vifctl.network('start') - threads = [] - for server in self.servers: - thread = Thread(target=server.run, name=server.__class__.__name__) - if isinstance(server, HttpServer): - thread.setDaemon(True) - thread.start() - threads.append(thread) - - - # check for when all threads have initialized themselves and then - # close the status pipe - - threads_left = True - while threads_left: - threads_left = False - - for server in self.servers: - if not server.ready: - threads_left = True - break - - if threads_left: - time.sleep(.5) - - if status: - status.write('0') - status.close() # Prepare to catch SIGTERM (received when 'xend stop' is executed) # and call each server's cleanup if possible signal.signal(signal.SIGTERM, self.cleanup) + signal.signal(signal.SIGHUP, self.reloadConfig) - # Interruptible Thread.join - Python Bug #1167930 - # Replaces: for t in threads: t.join() - # Reason: The above will cause python signal handlers to be - # blocked so we're not able to catch SIGTERM in any - # way for cleanup - runningThreads = threads - while len(runningThreads) > 0: - try: - for t in threads: - t.join(1.0) - runningThreads = [t for t in threads - if t.isAlive() and not t.isDaemon()] - if self.cleaningUp and len(runningThreads) > 0: - log.debug("Waiting for %s." % - [x.getName() for x in runningThreads]) - except: - pass + while True: + threads = [] + for server in self.servers: + thread = Thread(target=server.run, name=server.__class__.__name__) + if isinstance(server, HttpServer): + thread.setDaemon(True) + thread.start() + threads.append(thread) -def create(): - root = SrvDir() - root.putChild('xend', SrvRoot()) - servers = XendServers() + # check for when all threads have initialized themselves and then + # close the status pipe + + threads_left = True + while threads_left: + threads_left = False + + for server in self.servers: + if not server.ready: + threads_left = True + break + + if threads_left: + time.sleep(.5) + + if status: + status.write('0') + status.close() + status = None + + # Interruptible Thread.join - Python Bug #1167930 + # Replaces: for t in threads: t.join() + # Reason: The above will cause python signal handlers to be + # blocked so we're not able to catch SIGTERM in any + # way for cleanup + runningThreads = threads + while len(runningThreads) > 0: + try: + for t in threads: + t.join(1.0) + runningThreads = [t for t in threads + if t.isAlive() and not t.isDaemon()] + if self.cleaningUp and len(runningThreads) > 0: + log.debug("Waiting for %s." % + [x.getName() for x in runningThreads]) + except: + pass + + if self.reloadingConfig: + log.info("Restarting all servers...") + self.cleaningUp = False + self.reloadingConfig = False + xroot.set_config() + self.servers = [] + _loadConfig(self) + else: + break + +def _loadConfig(servers): if xroot.get_xend_http_server(): servers.add(HttpServer(root, xroot.get_xend_address(), @@ -188,4 +204,11 @@ def create(): if xroot.get_xend_unix_xmlrpc_server(): servers.add(XMLRPCServer(XendAPI.AUTH_PAM)) + + +def create(): + root = SrvDir() + root.putChild('xend', SrvRoot()) + servers = XendServers() + _loadConfig(servers) return servers From bcf6d372d8bb4772e77880d13fb47b6f32c97da1 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 13:56:27 +0000 Subject: [PATCH 176/282] Diagnose a failing server, rather than just locking up the whole daemon. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvServer.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 1b0ed9c0db..6bfff3a318 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -111,6 +111,7 @@ class XendServers: # check for when all threads have initialized themselves and then # close the status pipe + retryCount = 0 threads_left = True while threads_left: threads_left = False @@ -122,6 +123,14 @@ class XendServers: if threads_left: time.sleep(.5) + retryCount += 1 + if retryCount > 60: + for server in self.servers: + if not server.ready: + log.error("Server " + + server.__class__.__name__ + + " did not initialise!") + break if status: status.write('0') From 549aad081dd9b21f551edfdd16746de8a67aecf0 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 13:57:18 +0000 Subject: [PATCH 177/282] Close the server when instructed, so that we can reload on the same port, and diagnose a server that fails to start. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/XMLRPCServer.py | 40 +++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/tools/python/xen/xend/server/XMLRPCServer.py b/tools/python/xen/xend/server/XMLRPCServer.py index 45540995bd..c29b4b6bdd 100644 --- a/tools/python/xen/xend/server/XMLRPCServer.py +++ b/tools/python/xen/xend/server/XMLRPCServer.py @@ -16,6 +16,8 @@ # Copyright (C) 2006 XenSource Ltd. #============================================================================ +import errno +import socket import types import xmlrpclib from xen.util.xmlrpclib2 import UnixXMLRPCServer, TCPXMLRPCServer @@ -105,20 +107,25 @@ class XMLRPCServer: "; authentication has been disabled for this server." or ".") - if self.use_tcp: - log.info("Opening TCP XML-RPC server on %s%d%s", - self.host and '%s:' % self.host or - 'all interfaces, port ', - self.port, authmsg) - self.server = TCPXMLRPCServer((self.host, self.port), - self.hosts_allowed, - logRequests = False) - else: - log.info("Opening Unix domain socket XML-RPC server on %s%s", - self.path, authmsg) - self.server = UnixXMLRPCServer(self.path, self.hosts_allowed, - logRequests = False) - + try: + if self.use_tcp: + log.info("Opening TCP XML-RPC server on %s%d%s", + self.host and '%s:' % self.host or + 'all interfaces, port ', + self.port, authmsg) + self.server = TCPXMLRPCServer((self.host, self.port), + self.hosts_allowed, + logRequests = False) + else: + log.info("Opening Unix domain socket XML-RPC server on %s%s", + self.path, authmsg) + self.server = UnixXMLRPCServer(self.path, self.hosts_allowed, + logRequests = False) + except socket.error, exn: + log.error('Cannot start server: %s!', exn.args[1]) + ready = True + running = False + return # Register Xen API Functions # ------------------------------------------------------------------- @@ -177,6 +184,11 @@ class XMLRPCServer: def cleanup(self): log.debug("XMLRPCServer.cleanup()") + try: + self.server.socket.close() + except Exception, exn: + log.exception(exn) + pass def shutdown(self): self.running = False From 79b81fb253f65843ff49dfa9ef95dfb6933c69f2 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 4 Dec 2006 08:26:48 -0700 Subject: [PATCH 178/282] [IA64] add MCA softirqs to arch-specific header Signed-off-by: Alex Williamson --- xen/include/asm-ia64/softirq.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xen/include/asm-ia64/softirq.h b/xen/include/asm-ia64/softirq.h index 3444d300c0..9e5a03c482 100644 --- a/xen/include/asm-ia64/softirq.h +++ b/xen/include/asm-ia64/softirq.h @@ -1,6 +1,9 @@ #ifndef __ASM_SOFTIRQ_H__ #define __ASM_SOFTIRQ_H__ -#define NR_ARCH_SOFTIRQS 0 +#define CMC_DISABLE_SOFTIRQ (NR_COMMON_SOFTIRQS + 0) +#define CMC_ENABLE_SOFTIRQ (NR_COMMON_SOFTIRQS + 1) + +#define NR_ARCH_SOFTIRQS 2 #endif /* __ASM_SOFTIRQ_H__ */ From fdc1fbb4df038b7accc2dfec5447268d7bb3adb1 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 4 Dec 2006 08:28:44 -0700 Subject: [PATCH 179/282] [IA64] remove old xen_regs define from arch header This looks like cruft and conflicts with kexec Signed-off-by: Alex Williamson --- xen/include/asm-ia64/regs.h | 1 - 1 file changed, 1 deletion(-) diff --git a/xen/include/asm-ia64/regs.h b/xen/include/asm-ia64/regs.h index e429039f1f..9cbd09ec72 100644 --- a/xen/include/asm-ia64/regs.h +++ b/xen/include/asm-ia64/regs.h @@ -1,2 +1 @@ #include -#define xen_regs pt_regs From 9c5c2a1c0f19615fbd097d5e80de9cf8e14fbc63 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 4 Dec 2006 08:37:20 -0700 Subject: [PATCH 180/282] [IA64] import linux/include/asm-ia64/uaccess.h for /dev/mem paravirtualization Signed-off-by: Isaku Yamahata --- .../include/asm-ia64/uaccess.h | 401 ++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 linux-2.6-xen-sparse/include/asm-ia64/uaccess.h diff --git a/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h b/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h new file mode 100644 index 0000000000..9adb51211c --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h @@ -0,0 +1,401 @@ +#ifndef _ASM_IA64_UACCESS_H +#define _ASM_IA64_UACCESS_H + +/* + * This file defines various macros to transfer memory areas across + * the user/kernel boundary. This needs to be done carefully because + * this code is executed in kernel mode and uses user-specified + * addresses. Thus, we need to be careful not to let the user to + * trick us into accessing kernel memory that would normally be + * inaccessible. This code is also fairly performance sensitive, + * so we want to spend as little time doing safety checks as + * possible. + * + * To make matters a bit more interesting, these macros sometimes also + * called from within the kernel itself, in which case the address + * validity check must be skipped. The get_fs() macro tells us what + * to do: if get_fs()==USER_DS, checking is performed, if + * get_fs()==KERNEL_DS, checking is bypassed. + * + * Note that even if the memory area specified by the user is in a + * valid address range, it is still possible that we'll get a page + * fault while accessing it. This is handled by filling out an + * exception handler fixup entry for each instruction that has the + * potential to fault. When such a fault occurs, the page fault + * handler checks to see whether the faulting instruction has a fixup + * associated and, if so, sets r8 to -EFAULT and clears r9 to 0 and + * then resumes execution at the continuation point. + * + * Based on . + * + * Copyright (C) 1998, 1999, 2001-2004 Hewlett-Packard Co + * David Mosberger-Tang + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * For historical reasons, the following macros are grossly misnamed: + */ +#define KERNEL_DS ((mm_segment_t) { ~0UL }) /* cf. access_ok() */ +#define USER_DS ((mm_segment_t) { TASK_SIZE-1 }) /* cf. access_ok() */ + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + +#define segment_eq(a, b) ((a).seg == (b).seg) + +/* + * When accessing user memory, we need to make sure the entire area really is in + * user-level space. In order to do this efficiently, we make sure that the page at + * address TASK_SIZE is never valid. We also need to make sure that the address doesn't + * point inside the virtually mapped linear page table. + */ +#define __access_ok(addr, size, segment) \ +({ \ + __chk_user_ptr(addr); \ + (likely((unsigned long) (addr) <= (segment).seg) \ + && ((segment).seg == KERNEL_DS.seg \ + || likely(REGION_OFFSET((unsigned long) (addr)) < RGN_MAP_LIMIT))); \ +}) +#define access_ok(type, addr, size) __access_ok((addr), (size), get_fs()) + +/* + * These are the main single-value transfer routines. They automatically + * use the right size if we just have the right pointer type. + * + * Careful to not + * (a) re-use the arguments for side effects (sizeof/typeof is ok) + * (b) require any knowledge of processes at this stage + */ +#define put_user(x, ptr) __put_user_check((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr)), get_fs()) +#define get_user(x, ptr) __get_user_check((x), (ptr), sizeof(*(ptr)), get_fs()) + +/* + * The "__xxx" versions do not do address space checking, useful when + * doing multiple accesses to the same area (the programmer has to do the + * checks by hand with "access_ok()") + */ +#define __put_user(x, ptr) __put_user_nocheck((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr))) +#define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) + +extern long __put_user_unaligned_unknown (void); + +#define __put_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __put_user((x), (ptr)); break; \ + case 2: __ret = (__put_user((x), (u8 __user *)(ptr))) \ + | (__put_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__put_user((x), (u16 __user *)(ptr))) \ + | (__put_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__put_user((x), (u32 __user *)(ptr))) \ + | (__put_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __put_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + +extern long __get_user_unaligned_unknown (void); + +#define __get_user_unaligned(x, ptr) \ +({ \ + long __ret; \ + switch (sizeof(*(ptr))) { \ + case 1: __ret = __get_user((x), (ptr)); break; \ + case 2: __ret = (__get_user((x), (u8 __user *)(ptr))) \ + | (__get_user((x) >> 8, ((u8 __user *)(ptr) + 1))); break; \ + case 4: __ret = (__get_user((x), (u16 __user *)(ptr))) \ + | (__get_user((x) >> 16, ((u16 __user *)(ptr) + 1))); break; \ + case 8: __ret = (__get_user((x), (u32 __user *)(ptr))) \ + | (__get_user((x) >> 32, ((u32 __user *)(ptr) + 1))); break; \ + default: __ret = __get_user_unaligned_unknown(); \ + } \ + __ret; \ +}) + +#ifdef ASM_SUPPORTED + struct __large_struct { unsigned long buf[100]; }; +# define __m(x) (*(struct __large_struct __user *)(x)) + +/* We need to declare the __ex_table section before we can use it in .xdata. */ +asm (".section \"__ex_table\", \"a\"\n\t.previous"); + +# define __get_user_size(val, addr, n, err) \ +do { \ + register long __gu_r8 asm ("r8") = 0; \ + register long __gu_r9 asm ("r9"); \ + asm ("\n[1:]\tld"#n" %0=%2%P2\t// %0 and %1 get overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", 1b-., 1f-.+4\n" \ + "[1:]" \ + : "=r"(__gu_r9), "=r"(__gu_r8) : "m"(__m(addr)), "1"(__gu_r8)); \ + (err) = __gu_r8; \ + (val) = __gu_r9; \ +} while (0) + +/* + * The "__put_user_size()" macro tells gcc it reads from memory instead of writing it. This + * is because they do not write to any memory gcc knows about, so there are no aliasing + * issues. + */ +# define __put_user_size(val, addr, n, err) \ +do { \ + register long __pu_r8 asm ("r8") = 0; \ + asm volatile ("\n[1:]\tst"#n" %1=%r2%P1\t// %0 gets overwritten by exception handler\n" \ + "\t.xdata4 \"__ex_table\", 1b-., 1f-.\n" \ + "[1:]" \ + : "=r"(__pu_r8) : "m"(__m(addr)), "rO"(val), "0"(__pu_r8)); \ + (err) = __pu_r8; \ +} while (0) + +#else /* !ASM_SUPPORTED */ +# define RELOC_TYPE 2 /* ip-rel */ +# define __get_user_size(val, addr, n, err) \ +do { \ + __ld_user("__ex_table", (unsigned long) addr, n, RELOC_TYPE); \ + (err) = ia64_getreg(_IA64_REG_R8); \ + (val) = ia64_getreg(_IA64_REG_R9); \ +} while (0) +# define __put_user_size(val, addr, n, err) \ +do { \ + __st_user("__ex_table", (unsigned long) addr, n, RELOC_TYPE, (unsigned long) (val)); \ + (err) = ia64_getreg(_IA64_REG_R8); \ +} while (0) +#endif /* !ASM_SUPPORTED */ + +extern void __get_user_unknown (void); + +/* + * Evaluating arguments X, PTR, SIZE, and SEGMENT may involve subroutine-calls, which + * could clobber r8 and r9 (among others). Thus, be careful not to evaluate it while + * using r8/r9. + */ +#define __do_get_user(check, x, ptr, size, segment) \ +({ \ + const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \ + __typeof__ (size) __gu_size = (size); \ + long __gu_err = -EFAULT; \ + unsigned long __gu_val = 0; \ + if (!check || __access_ok(__gu_ptr, size, segment)) \ + switch (__gu_size) { \ + case 1: __get_user_size(__gu_val, __gu_ptr, 1, __gu_err); break; \ + case 2: __get_user_size(__gu_val, __gu_ptr, 2, __gu_err); break; \ + case 4: __get_user_size(__gu_val, __gu_ptr, 4, __gu_err); break; \ + case 8: __get_user_size(__gu_val, __gu_ptr, 8, __gu_err); break; \ + default: __get_user_unknown(); break; \ + } \ + (x) = (__typeof__(*(__gu_ptr))) __gu_val; \ + __gu_err; \ +}) + +#define __get_user_nocheck(x, ptr, size) __do_get_user(0, x, ptr, size, KERNEL_DS) +#define __get_user_check(x, ptr, size, segment) __do_get_user(1, x, ptr, size, segment) + +extern void __put_user_unknown (void); + +/* + * Evaluating arguments X, PTR, SIZE, and SEGMENT may involve subroutine-calls, which + * could clobber r8 (among others). Thus, be careful not to evaluate them while using r8. + */ +#define __do_put_user(check, x, ptr, size, segment) \ +({ \ + __typeof__ (x) __pu_x = (x); \ + __typeof__ (*(ptr)) __user *__pu_ptr = (ptr); \ + __typeof__ (size) __pu_size = (size); \ + long __pu_err = -EFAULT; \ + \ + if (!check || __access_ok(__pu_ptr, __pu_size, segment)) \ + switch (__pu_size) { \ + case 1: __put_user_size(__pu_x, __pu_ptr, 1, __pu_err); break; \ + case 2: __put_user_size(__pu_x, __pu_ptr, 2, __pu_err); break; \ + case 4: __put_user_size(__pu_x, __pu_ptr, 4, __pu_err); break; \ + case 8: __put_user_size(__pu_x, __pu_ptr, 8, __pu_err); break; \ + default: __put_user_unknown(); break; \ + } \ + __pu_err; \ +}) + +#define __put_user_nocheck(x, ptr, size) __do_put_user(0, x, ptr, size, KERNEL_DS) +#define __put_user_check(x, ptr, size, segment) __do_put_user(1, x, ptr, size, segment) + +/* + * Complex access routines + */ +extern unsigned long __must_check __copy_user (void __user *to, const void __user *from, + unsigned long count); + +static inline unsigned long +__copy_to_user (void __user *to, const void *from, unsigned long count) +{ + return __copy_user(to, (__force void __user *) from, count); +} + +static inline unsigned long +__copy_from_user (void *to, const void __user *from, unsigned long count) +{ + return __copy_user((__force void __user *) to, from, count); +} + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user +#define copy_to_user(to, from, n) \ +({ \ + void __user *__cu_to = (to); \ + const void *__cu_from = (from); \ + long __cu_len = (n); \ + \ + if (__access_ok(__cu_to, __cu_len, get_fs())) \ + __cu_len = __copy_user(__cu_to, (__force void __user *) __cu_from, __cu_len); \ + __cu_len; \ +}) + +#define copy_from_user(to, from, n) \ +({ \ + void *__cu_to = (to); \ + const void __user *__cu_from = (from); \ + long __cu_len = (n); \ + \ + __chk_user_ptr(__cu_from); \ + if (__access_ok(__cu_from, __cu_len, get_fs())) \ + __cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len); \ + __cu_len; \ +}) + +#define __copy_in_user(to, from, size) __copy_user((to), (from), (size)) + +static inline unsigned long +copy_in_user (void __user *to, const void __user *from, unsigned long n) +{ + if (likely(access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n))) + n = __copy_user(to, from, n); + return n; +} + +extern unsigned long __do_clear_user (void __user *, unsigned long); + +#define __clear_user(to, n) __do_clear_user(to, n) + +#define clear_user(to, n) \ +({ \ + unsigned long __cu_len = (n); \ + if (__access_ok(to, __cu_len, get_fs())) \ + __cu_len = __do_clear_user(to, __cu_len); \ + __cu_len; \ +}) + + +/* + * Returns: -EFAULT if exception before terminator, N if the entire buffer filled, else + * strlen. + */ +extern long __must_check __strncpy_from_user (char *to, const char __user *from, long to_len); + +#define strncpy_from_user(to, from, n) \ +({ \ + const char __user * __sfu_from = (from); \ + long __sfu_ret = -EFAULT; \ + if (__access_ok(__sfu_from, 0, get_fs())) \ + __sfu_ret = __strncpy_from_user((to), __sfu_from, (n)); \ + __sfu_ret; \ +}) + +/* Returns: 0 if bad, string length+1 (memory size) of string if ok */ +extern unsigned long __strlen_user (const char __user *); + +#define strlen_user(str) \ +({ \ + const char __user *__su_str = (str); \ + unsigned long __su_ret = 0; \ + if (__access_ok(__su_str, 0, get_fs())) \ + __su_ret = __strlen_user(__su_str); \ + __su_ret; \ +}) + +/* + * Returns: 0 if exception before NUL or reaching the supplied limit + * (N), a value greater than N if the limit would be exceeded, else + * strlen. + */ +extern unsigned long __strnlen_user (const char __user *, long); + +#define strnlen_user(str, len) \ +({ \ + const char __user *__su_str = (str); \ + unsigned long __su_ret = 0; \ + if (__access_ok(__su_str, 0, get_fs())) \ + __su_ret = __strnlen_user(__su_str, len); \ + __su_ret; \ +}) + +/* Generic code can't deal with the location-relative format that we use for compactness. */ +#define ARCH_HAS_SORT_EXTABLE +#define ARCH_HAS_SEARCH_EXTABLE + +struct exception_table_entry { + int addr; /* location-relative address of insn this fixup is for */ + int cont; /* location-relative continuation addr.; if bit 2 is set, r9 is set to 0 */ +}; + +extern void ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e); +extern const struct exception_table_entry *search_exception_tables (unsigned long addr); + +static inline int +ia64_done_with_exception (struct pt_regs *regs) +{ + const struct exception_table_entry *e; + e = search_exception_tables(regs->cr_iip + ia64_psr(regs)->ri); + if (e) { + ia64_handle_exception(regs, e); + return 1; + } + return 0; +} + +#define ARCH_HAS_TRANSLATE_MEM_PTR 1 +static __inline__ char * +xlate_dev_mem_ptr (unsigned long p) +{ + struct page *page; + char * ptr; + + page = pfn_to_page(p >> PAGE_SHIFT); + if (PageUncached(page)) + ptr = (char *)p + __IA64_UNCACHED_OFFSET; + else + ptr = __va(p); + + return ptr; +} + +/* + * Convert a virtual cached kernel memory pointer to an uncached pointer + */ +static __inline__ char * +xlate_dev_kmem_ptr (char * p) +{ + struct page *page; + char * ptr; + + page = virt_to_page((unsigned long)p >> PAGE_SHIFT); + if (PageUncached(page)) + ptr = (char *)__pa(p) + __IA64_UNCACHED_OFFSET; + else + ptr = p; + + return ptr; +} + +#endif /* _ASM_IA64_UACCESS_H */ From bd4a1b45bf9dbf43d375c3f46953eac79de09d20 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Mon, 4 Dec 2006 08:44:57 -0700 Subject: [PATCH 181/282] [IA64] paraviatualize /dev/mem to enable X. Signed-off-by: Isaku Yamahata --- linux-2.6-xen-sparse/arch/ia64/Kconfig | 3 - linux-2.6-xen-sparse/arch/ia64/xen/Makefile | 2 +- linux-2.6-xen-sparse/arch/ia64/xen/mem.c | 76 +++++++++++++++++++ linux-2.6-xen-sparse/include/asm-ia64/io.h | 7 ++ .../include/asm-ia64/uaccess.h | 20 +++++ 5 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 linux-2.6-xen-sparse/arch/ia64/xen/mem.c diff --git a/linux-2.6-xen-sparse/arch/ia64/Kconfig b/linux-2.6-xen-sparse/arch/ia64/Kconfig index 4073a04638..5a3768d779 100644 --- a/linux-2.6-xen-sparse/arch/ia64/Kconfig +++ b/linux-2.6-xen-sparse/arch/ia64/Kconfig @@ -533,9 +533,6 @@ config XEN_BALLOON config XEN_SKBUFF default y -config XEN_DEVMEM - default n - config XEN_REBOOT default y diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile index 36434aac72..6bd31af099 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile +++ b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile @@ -4,6 +4,6 @@ obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \ hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \ - xcom_mini.o xcom_privcmd.o + xcom_mini.o xcom_privcmd.o mem.o pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/mem.c b/linux-2.6-xen-sparse/arch/ia64/xen/mem.c new file mode 100644 index 0000000000..1c995b6f11 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/xen/mem.c @@ -0,0 +1,76 @@ +/* + * Originally from linux/drivers/char/mem.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Added devfs support. + * Jan-11-1998, C. Scott Ananian + * Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar + */ +/* + * taken from + * linux/drivers/char/mem.c and linux-2.6-xen-sparse/drivers/xen/char/mem.c. + * adjusted for IA64 and made transparent. + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + */ + +#include +#include +#include + +/* + * Architectures vary in how they handle caching for addresses + * outside of main memory. + * + */ +static inline int uncached_access(struct file *file, unsigned long addr) +{ + /* + * On ia64, we ignore O_SYNC because we cannot tolerate memory attribute aliases. + */ + return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); +} + +int xen_mmap_mem(struct file * file, struct vm_area_struct * vma) +{ + unsigned long addr = vma->vm_pgoff << PAGE_SHIFT; + size_t size = vma->vm_end - vma->vm_start; + + +#if 0 + /* + *XXX FIXME: linux-2.6.16.29, linux-2.6.17 + * valid_mmap_phys_addr_range() in linux/arch/ia64/kernel/efi.c + * fails checks. + * linux-2.6.18.1's returns always 1. + * Its comments says + * + * MMIO regions are often missing from the EFI memory map. + * We must allow mmap of them for programs like X, so we + * currently can't do any useful validation. + */ + if (!valid_mmap_phys_addr_range(addr, &size)) + return -EINVAL; + if (size < vma->vm_end - vma->vm_start) + return -EINVAL; +#endif + + if (is_running_on_xen()) { + unsigned long offset = HYPERVISOR_ioremap(addr, size); + if (IS_ERR_VALUE(offset)) + return offset; + } + + if (uncached_access(file, vma->vm_pgoff << PAGE_SHIFT)) + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ + if (remap_pfn_range(vma, + vma->vm_start, + vma->vm_pgoff, + size, + vma->vm_page_prot)) + return -EAGAIN; + return 0; +} diff --git a/linux-2.6-xen-sparse/include/asm-ia64/io.h b/linux-2.6-xen-sparse/include/asm-ia64/io.h index a841d78d79..73c9b60904 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/io.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/io.h @@ -129,6 +129,11 @@ extern int valid_mmap_phys_addr_range (unsigned long addr, size_t *count); (((bvec_to_bus((vec1)) + (vec1)->bv_len) == bvec_to_bus((vec2))) && \ ((bvec_to_pseudophys((vec1)) + (vec1)->bv_len) == \ bvec_to_pseudophys((vec2)))) + +/* We will be supplying our own /dev/mem implementation */ +#define ARCH_HAS_DEV_MEM +#define ARCH_HAS_DEV_MEM_MMAP_MEM +int xen_mmap_mem(struct file * file, struct vm_area_struct * vma); #endif /* CONFIG_XEN */ # endif /* KERNEL */ @@ -458,6 +463,8 @@ static inline void __iomem * ioremap (unsigned long offset, unsigned long size) { offset = HYPERVISOR_ioremap(offset, size); + if (IS_ERR_VALUE(offset)) + return (void __iomem*)offset; return (void __iomem *) (__IA64_UNCACHED_OFFSET | (offset)); } diff --git a/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h b/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h index 9adb51211c..e015fd0d3b 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/uaccess.h @@ -365,6 +365,7 @@ ia64_done_with_exception (struct pt_regs *regs) } #define ARCH_HAS_TRANSLATE_MEM_PTR 1 +#ifndef CONFIG_XEN static __inline__ char * xlate_dev_mem_ptr (unsigned long p) { @@ -379,6 +380,25 @@ xlate_dev_mem_ptr (unsigned long p) return ptr; } +#else +static __inline__ char * +xlate_dev_mem_ptr (unsigned long p, ssize_t sz) +{ + unsigned long pfn = p >> PAGE_SHIFT; + + if (pfn_valid(pfn) && !PageUncached(pfn_to_page(pfn))) + return __va(p); + + return ioremap(p, sz); +} + +static __inline__ void +xlate_dev_mem_ptr_unmap (char* v) +{ + if (REGION_NUMBER(v) == RGN_UNCACHED) + iounmap(v); +} +#endif /* * Convert a virtual cached kernel memory pointer to an uncached pointer From 4a0a4459e934bc73e3bce714bfd01c16e90c7ce2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 17:52:33 +0000 Subject: [PATCH 182/282] Fix numpad handling in QEMU's VNC server. The keymaps that we have include information on which keys change depending upon the numlock setting, but this isn't being used. By forcing numlock on and off as necessary, when receiving these keysyms through the VNC connection, we ensure that the server's numlock status is the same as the client's. Signed-off-by: Ewan Mellor --- tools/ioemu/keymaps.c | 63 ++++++++++++++++++++++++++++++++++++++-- tools/ioemu/vnc.c | 32 ++++++++++++++++++++ tools/ioemu/vnc_keysym.h | 14 +++++++++ 3 files changed, 107 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/keymaps.c b/tools/ioemu/keymaps.c index bd893288aa..e7dd4a8b11 100644 --- a/tools/ioemu/keymaps.c +++ b/tools/ioemu/keymaps.c @@ -36,8 +36,10 @@ static int get_keysym(const char *name) #define MAX_EXTRA_COUNT 256 typedef struct { uint16_t keysym2keycode[MAX_NORMAL_KEYCODE]; + int keysym2numlock[MAX_NORMAL_KEYCODE]; struct { int keysym; + int numlock; uint16_t keycode; } keysym2keycode_extra[MAX_EXTRA_COUNT]; int extra_count; @@ -50,6 +52,8 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, char file_name[1024]; char line[1024]; int len; + int *keycode2numlock; + int i; snprintf(file_name, sizeof(file_name), "%s/keymaps/%s", bios_dir, language); @@ -63,6 +67,15 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, "Could not read keymap file: '%s'\n", file_name); return 0; } + + /* Allocate a temporary map tracking which keycodes change when numlock is + set. Keycodes are 16 bit, so 65536 is safe. */ + keycode2numlock = malloc(65536 * sizeof(int)); + if (!keycode2numlock) { + perror("Could not read keymap file"); + return 0; + } + for(;;) { if (fgets(line, 1024, f) == NULL) break; @@ -86,13 +99,19 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, if (keysym == 0) { // fprintf(stderr, "Warning: unknown keysym %s\n", line); } else { - const char *rest = end_of_keysym + 1; - int keycode = strtol(rest, NULL, 0); + char *rest = end_of_keysym + 1; + int keycode = strtol(rest, &rest, 0); + int numlock = (rest != NULL && + strstr(rest, "numlock") != NULL); + + keycode2numlock[keycode] = numlock; + /* if(keycode&0x80) keycode=(keycode<<8)^0x80e0; */ if (keysym < MAX_NORMAL_KEYCODE) { //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); k->keysym2keycode[keysym] = keycode; + k->keysym2numlock[keysym] = numlock; } else { if (k->extra_count >= MAX_EXTRA_COUNT) { fprintf(stderr, @@ -107,6 +126,8 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, keysym = keysym; k->keysym2keycode_extra[k->extra_count]. keycode = keycode; + k->keysym2keycode_extra[k->extra_count]. + numlock = numlock; k->extra_count++; } } @@ -115,6 +136,22 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, } } fclose(f); + + for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) { + if (k->keysym2numlock[i] != 1) { + k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]]; + } + } + + for (int i = 0; i < k->extra_count; i++) { + if (k->keysym2keycode_extra[i].numlock != 1) { + k->keysym2keycode_extra[i].numlock = + -keycode2numlock[k->keysym2keycode_extra[i].keycode]; + } + } + + free(keycode2numlock); + return k; } @@ -143,3 +180,25 @@ static int keysym2scancode(void *kbd_layout, int keysym) } return 0; } + +/** + * Returns 1 if the given keysym requires numlock to be pressed, -1 if it + * requires it to be cleared, and 0 otherwise. + */ +static int keysym2numlock(void *kbd_layout, int keysym) +{ + kbd_layout_t *k = kbd_layout; + if (keysym < MAX_NORMAL_KEYCODE) { + return k->keysym2numlock[keysym]; + } else { + int i; +#ifdef XK_ISO_Left_Tab + if (keysym == XK_ISO_Left_Tab) + keysym = XK_Tab; +#endif + for (i = 0; i < k->extra_count; i++) + if (k->keysym2keycode_extra[i].keysym == keysym) + return k->keysym2keycode_extra[i].numlock; + } + return 0; +} diff --git a/tools/ioemu/vnc.c b/tools/ioemu/vnc.c index 86d3720f90..6d7cc31d4a 100644 --- a/tools/ioemu/vnc.c +++ b/tools/ioemu/vnc.c @@ -115,6 +115,7 @@ struct VncState int ctl_keys; /* Ctrl+Alt starts calibration */ int shift_keys; /* Shift / CapsLock keys */ + int numlock; }; #define DIRTY_PIXEL_BITS 64 @@ -854,14 +855,40 @@ static void pointer_event(VncState *vs, int button_mask, int x, int y) } } +static void press_key(VncState *vs, int keycode) +{ + kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) & 0x7f); + kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) | 0x80); +} + static void do_key_event(VncState *vs, int down, uint32_t sym) { sym &= 0xFFFF; if (is_graphic_console()) { int keycode; + int numlock; keycode = keysym2scancode(vs->kbd_layout, sym); + numlock = keysym2numlock(vs->kbd_layout, sym); + + /* If the numlock state needs to change then simulate an additional + keypress before sending this one. This will happen if the user + toggles numlock away from the VNC window. + */ + if (numlock == 1) { + if (!vs->numlock) { + vs->numlock = 1; + press_key(vs, XK_Num_Lock); + } + } + else if (numlock == -1) { + if (vs->numlock) { + vs->numlock = 0; + press_key(vs, XK_Num_Lock); + } + } + if (keycode & 0x80) kbd_put_keycode(0xe0); if (down) @@ -932,6 +959,10 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) vs->shift_keys ^= 2; break; + case XK_Num_Lock: + vs->numlock = !vs->numlock; + break; + case XK_1 ... XK_9: if ((vs->ctl_keys & 3) != 3) break; @@ -1355,6 +1386,7 @@ int vnc_display_init(DisplayState *ds, int display, int find_unused, struct sock vs->lsock = -1; vs->csock = -1; vs->depth = 4; + vs->numlock = 0; vs->ds = ds; diff --git a/tools/ioemu/vnc_keysym.h b/tools/ioemu/vnc_keysym.h index 14fe47f9e1..5c47104442 100644 --- a/tools/ioemu/vnc_keysym.h +++ b/tools/ioemu/vnc_keysym.h @@ -231,6 +231,19 @@ static name2keysym_t name2keysym[]={ {"Home", 0xff50}, /* XK_Home */ {"End", 0xff57}, /* XK_End */ {"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */ +{"KP_Home", 0xff95}, +{"KP_Left", 0xff96}, +{"KP_Up", 0xff97}, +{"KP_Right", 0xff98}, +{"KP_Down", 0xff99}, +{"KP_Prior", 0xff9a}, +{"KP_Page_Up", 0xff9a}, +{"KP_Next", 0xff9b}, +{"KP_Page_Down", 0xff9b}, +{"KP_End", 0xff9c}, +{"KP_Begin", 0xff9d}, +{"KP_Insert", 0xff9e}, +{"KP_Delete", 0xff9f}, {"F1", 0xffbe}, /* XK_F1 */ {"F2", 0xffbf}, /* XK_F2 */ {"F3", 0xffc0}, /* XK_F3 */ @@ -258,6 +271,7 @@ static name2keysym_t name2keysym[]={ {"KP_8", 0xffb8}, /* XK_KP_8 */ {"KP_9", 0xffb9}, /* XK_KP_9 */ {"KP_Add", 0xffab}, /* XK_KP_Add */ +{"KP_Separator", 0xffac},/* XK_KP_Separator */ {"KP_Decimal", 0xffae}, /* XK_KP_Decimal */ {"KP_Divide", 0xffaf}, /* XK_KP_Divide */ {"KP_Enter", 0xff8d}, /* XK_KP_Enter */ From bb34321ece2d83d8b9b76cf3898ed1e0bf5fc8c2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 18:05:32 +0000 Subject: [PATCH 183/282] Tidy. Signed-off-by: Ewan Mellor --- tools/ioemu/keymaps.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ioemu/keymaps.c b/tools/ioemu/keymaps.c index e7dd4a8b11..b86ab2a0b0 100644 --- a/tools/ioemu/keymaps.c +++ b/tools/ioemu/keymaps.c @@ -137,13 +137,13 @@ static kbd_layout_t *parse_keyboard_layout(const char *language, } fclose(f); - for (int i = 0; i < MAX_NORMAL_KEYCODE; i++) { + for (i = 0; i < MAX_NORMAL_KEYCODE; i++) { if (k->keysym2numlock[i] != 1) { k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]]; } } - for (int i = 0; i < k->extra_count; i++) { + for (i = 0; i < k->extra_count; i++) { if (k->keysym2keycode_extra[i].numlock != 1) { k->keysym2keycode_extra[i].numlock = -keycode2numlock[k->keysym2keycode_extra[i].keycode]; From 89ebc69e6a6a0ee090c1e04c8a704a1b2ce16eb1 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Mon, 4 Dec 2006 19:13:55 +0000 Subject: [PATCH 184/282] This adds a recently added parameter to the vm.start call. Signed-off-by: Stefan Berger --- tools/xm-test/lib/XmTestLib/XenManagedDomain.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/xm-test/lib/XmTestLib/XenManagedDomain.py b/tools/xm-test/lib/XmTestLib/XenManagedDomain.py index 94fbe44d3e..1b211fe016 100644 --- a/tools/xm-test/lib/XmTestLib/XenManagedDomain.py +++ b/tools/xm-test/lib/XmTestLib/XenManagedDomain.py @@ -94,12 +94,13 @@ class XenManagedDomain(XenDomain): #Only support PV for now. self.type = "PV" - def start(self, noConsole=False): + def start(self, noConsole=False, startpaused=False): #start the VM server = self.server if self.vm_uuid: try: - xapi.execute(server.VM.start, self.session, self.vm_uuid) + xapi.execute(server.VM.start, self.session, self.vm_uuid, + startpaused) except: raise DomainError("Could not start domain") else: From e65d392f390523b99285af9dbcf31e25027f832a Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Tue, 5 Dec 2006 12:42:29 +0000 Subject: [PATCH 185/282] [XEN] sh_gfn_to_mfn_foreign() must handle guest pfns above 4GB on PAE Signed-off-by: Tim Deegan --- xen/arch/x86/mm/shadow/common.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index a109716c9f..1f295758d8 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1246,7 +1246,7 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) /* Read another domain's p2m entries */ { mfn_t mfn; - unsigned long addr = gpfn << PAGE_SHIFT; + paddr_t addr = ((paddr_t)gpfn) << PAGE_SHIFT; l2_pgentry_t *l2e; l1_pgentry_t *l1e; @@ -1274,7 +1274,16 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) #if CONFIG_PAGING_LEVELS >= 3 { l3_pgentry_t *l3e = sh_map_domain_page(mfn); - l3e += l3_table_offset(addr); +#if CONFIG_PAGING_LEVELS == 3 + /* On PAE hosts the p2m has eight l3 entries, not four (see + * shadow_set_p2m_entry()) so we can't use l3_table_offset. + * Instead, just count the number of l3es from zero. It's safe + * to do this because we already checked that the gfn is within + * the bounds of the p2m. */ + l3e += (((addr) & VADDR_MASK) >> L3_PAGETABLE_SHIFT); +#else + l3e += l3_table_offset(addr); +#endif if ( (l3e_get_flags(*l3e) & _PAGE_PRESENT) == 0 ) { sh_unmap_domain_page(l3e); From 8537fbaeade8b85d8751b2702b0b3e76dabaeff6 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Tue, 5 Dec 2006 17:01:34 +0000 Subject: [PATCH 186/282] [LINUX] The crash note resource should be nested inside the hypervisor resource. This was exposed by 12709:98413fa7826c which corrected the length of the hypervisor resource. Signed-off-by: Ian Campbell --- linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c index 88a2423340..1f4a828e55 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -106,7 +106,7 @@ void xen_machine_kexec_register_resources(struct resource *res) request_resource(res, &xen_hypervisor_res); for (k = 0; k < xen_max_nr_phys_cpus; k++) - request_resource(res, xen_phys_cpus + k); + request_resource(&xen_hypervisor_res, xen_phys_cpus + k); } From b988d46a49abccb54f11dc41618e2db41f0f2f77 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Wed, 6 Dec 2006 10:05:41 +0000 Subject: [PATCH 187/282] Fixes a mistake in changeset 12732 Signed-off-by: Xiaohui Xin Signed-off-by: Anthony Xu Signed-off-by: Dexuan Cui --- xen/arch/x86/mm/shadow/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 1f295758d8..881f91a81d 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1280,7 +1280,7 @@ sh_gfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) * Instead, just count the number of l3es from zero. It's safe * to do this because we already checked that the gfn is within * the bounds of the p2m. */ - l3e += (((addr) & VADDR_MASK) >> L3_PAGETABLE_SHIFT); + l3e += (addr >> L3_PAGETABLE_SHIFT); #else l3e += l3_table_offset(addr); #endif From ec168504b9564819c67b10521f0eb5896c518dd9 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Tue, 5 Dec 2006 15:47:43 +0000 Subject: [PATCH 188/282] Fix error message. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index 5ebb7e6240..cc3c5c783e 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -808,7 +808,7 @@ class XendDomain: raise XendError("Cannot save privileged domain %s" % domname) if dominfo.state != DOM_STATE_HALTED: - raise XendError("Cannot suspend domain that is not running.") + raise XendError("Cannot resume domain that is not halted.") dom_uuid = dominfo.get_uuid() chkpath = self._managed_check_point_path(dom_uuid) From f77ef48c1d5a5f2709bc375e9e121a0b160bad3b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 5 Dec 2006 09:09:44 -0700 Subject: [PATCH 189/282] [IA64][LIBXC] prep for fixes Groundwork for real fixes to follow Signed-off-by: Alex Williamson --- tools/libxc/ia64/xc_ia64_hvm_build.c | 27 ++++----------------------- tools/libxc/xc_linux_build.c | 3 +++ 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_hvm_build.c b/tools/libxc/ia64/xc_ia64_hvm_build.c index c12dfc3d84..325442b1b4 100644 --- a/tools/libxc/ia64/xc_ia64_hvm_build.c +++ b/tools/libxc/ia64/xc_ia64_hvm_build.c @@ -581,8 +581,7 @@ add_pal_hob(void* hob_buf) */ static int setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, - char *image, unsigned long image_size, uint32_t vcpus, - unsigned int store_evtchn, unsigned long *store_mfn) + char *image, unsigned long image_size, vcpu_guest_context_t *ctxt) { xen_pfn_t *pfn_list; shared_iopage_t *sp; @@ -669,11 +668,6 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, if (xc_domctl(xc_handle, &domctl)) goto error_out; - if (xc_domain_translate_gpfn_list(xc_handle, dom, nr_pages, - pfn_list, pfn_list)) { - PERROR("Could not translate addresses of HVM guest.\n"); - goto error_out; - } // Load guest firmware if (xc_ia64_copy_to_domain_pages(xc_handle, dom, image, @@ -692,10 +686,8 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, STORE_PAGE_START>>PAGE_SHIFT); - xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn); // Retrieve special pages like io, xenstore, etc. - *store_mfn = pfn_list[nr_pages - 2]; sp = (shared_iopage_t *)xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, pfn_list[nr_pages - 3]); @@ -717,12 +709,9 @@ error_out: } int -xc_hvm_build(int xc_handle, uint32_t domid, int memsize, - const char *image_name, unsigned int vcpus, unsigned int pae, - unsigned int acpi, unsigned int store_evtchn, - unsigned long *store_mfn) +xc_hvm_build(int xc_handle, uint32_t domid, int memsize, const char *image_name) { - struct xen_domctl launch_domctl, domctl; + struct xen_domctl launch_domctl; int rc; vcpu_guest_context_t st_ctxt, *ctxt = &st_ctxt; char *image = NULL; @@ -748,18 +737,10 @@ xc_hvm_build(int xc_handle, uint32_t domid, int memsize, return 1; } - domctl.cmd = XEN_DOMCTL_getdomaininfo; - domctl.domain = (domid_t)domid; - if (do_domctl(xc_handle, &domctl) < 0 || - (uint16_t)domctl.domain != domid) { - PERROR("Could not get info on domain"); - goto error_out; - } - memset(ctxt, 0, sizeof(*ctxt)); if (setup_guest(xc_handle, domid, (unsigned long)memsize, image, - image_size, vcpus, store_evtchn, store_mfn) < 0) { + image_size, ctxt) < 0) { ERROR("Error constructing guest OS"); goto error_out; } diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 9bd4a5e3f4..e3f68b6f00 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -565,6 +565,9 @@ static int setup_guest(int xc_handle, start_info = xc_map_foreign_range( xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[nr_pages - 3]); + if ( start_info == NULL ) + goto error_out; + memset(start_info, 0, sizeof(*start_info)); rc = xc_version(xc_handle, XENVER_version, NULL); sprintf(start_info->magic, "xen-%i.%i-ia64", rc >> 16, rc & (0xFFFF)); From 04d0fece67cf8c4e77b370a9e47636a9b6d53798 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 5 Dec 2006 09:44:24 -0700 Subject: [PATCH 190/282] [IA64] Fix VTi domain creation Signed-off-by: Zhang Xin --- tools/libxc/ia64/xc_ia64_hvm_build.c | 10 ++++++---- tools/python/xen/lowlevel/xc/xc.c | 13 ++++++++++++- xen/include/public/arch-ia64.h | 7 +++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_hvm_build.c b/tools/libxc/ia64/xc_ia64_hvm_build.c index 325442b1b4..a38728d73a 100644 --- a/tools/libxc/ia64/xc_ia64_hvm_build.c +++ b/tools/libxc/ia64/xc_ia64_hvm_build.c @@ -591,6 +591,7 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, unsigned long dom_memsize = ((memsize - 16) << 20); unsigned long nr_pages = (unsigned long)memsize << (20 - PAGE_SHIFT); unsigned long normal_pages = nr_pages - GFW_PAGES; + unsigned long vcpus; int rc; long i, j; DECLARE_DOMCTL; @@ -668,7 +669,6 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, if (xc_domctl(xc_handle, &domctl)) goto error_out; - // Load guest firmware if (xc_ia64_copy_to_domain_pages(xc_handle, dom, image, (GFW_START + GFW_SIZE - image_size) >> PAGE_SHIFT, @@ -677,15 +677,17 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, goto error_out; } + // Get number of vcpus, stored by pyxc_hvm_build() + xc_get_hvm_param(xc_handle, dom, HVM_PARAM_VCPUS, &vcpus); + // Hand-off state passed to guest firmware - if (xc_ia64_build_hob(xc_handle, dom, dom_memsize, - (unsigned long)vcpus) < 0) { + if (xc_ia64_build_hob(xc_handle, dom, dom_memsize, vcpus) < 0) { PERROR("Could not build hob\n"); goto error_out; } xc_set_hvm_param(xc_handle, dom, - HVM_PARAM_STORE_PFN, STORE_PAGE_START>>PAGE_SHIFT); + HVM_PARAM_STORE_PFN, pfn_list[nr_pages - 2]); // Retrieve special pages like io, xenstore, etc. sp = (shared_iopage_t *)xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 2eb9376426..48f85aa9dc 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -374,10 +374,13 @@ static PyObject *pyxc_hvm_build(XcObject *self, PyObject *kwds) { uint32_t dom; +#if !defined(__ia64__) struct hvm_info_table *va_hvm; uint8_t *va_map, sum; + int i; +#endif char *image; - int i, store_evtchn, memsize, vcpus = 1, pae = 0, acpi = 0, apic = 1; + int store_evtchn, memsize, vcpus = 1, pae = 0, acpi = 0, apic = 1; unsigned long store_mfn; static char *kwd_list[] = { "domid", "store_evtchn", @@ -388,9 +391,14 @@ static PyObject *pyxc_hvm_build(XcObject *self, &image, &vcpus, &pae, &acpi, &apic) ) return NULL; +#if defined(__ia64__) + /* Set vcpus to later be retrieved in setup_guest() */ + xc_set_hvm_param(self->xc_handle, dom, HVM_PARAM_VCPUS, vcpus); +#endif if ( xc_hvm_build(self->xc_handle, dom, memsize, image) != 0 ) return PyErr_SetFromErrno(xc_error); +#if !defined(__ia64__) /* Set up the HVM info table. */ va_map = xc_map_foreign_range(self->xc_handle, dom, XC_PAGE_SIZE, PROT_READ | PROT_WRITE, @@ -408,9 +416,12 @@ static PyObject *pyxc_hvm_build(XcObject *self, sum += ((uint8_t *)va_hvm)[i]; va_hvm->checksum = -sum; munmap(va_map, XC_PAGE_SIZE); +#endif xc_get_hvm_param(self->xc_handle, dom, HVM_PARAM_STORE_PFN, &store_mfn); +#if !defined(__ia64__) xc_set_hvm_param(self->xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae); +#endif xc_set_hvm_param(self->xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn); diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index 8125eacebb..f3b8e423b5 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -66,6 +66,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); /* WARNING: before changing this, check that shared_info fits on a page */ #define MAX_VIRT_CPUS 64 +/* + * HVM_PARAM_PAE_ENABLED is meaningless on ia64, so we overload this + * entry to store the number of vCPUs. XXX Need arch-specific extentions + * for xc_get/set_hvm_param(). + */ +#define HVM_PARAM_VCPUS HVM_PARAM_PAE_ENABLED + #ifndef __ASSEMBLY__ typedef unsigned long xen_ulong_t; From 0013d074cd16389a2a71e3f5d6d7637a55c3cdd7 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 5 Dec 2006 10:59:32 -0700 Subject: [PATCH 191/282] [IA64] changed foreign domain page mapping semantic. x86 foreign HVM domain page mapping semantic was changed to use gmfn instead mfn. It applies to domains with auto_translated_mode enabled, and all ia64 domains enable auto_translated_mode. This patch changes ia64 foreign domain page mapping to use gmfn and fixes ia64 domU buidler. However this patch breaks domain save/restore/dump-core. They should also be fixed-up Signed-off-by: Isaku Yamahata --- .../arch/ia64/xen/hypervisor.c | 12 ++--- .../include/asm-ia64/hypercall.h | 22 +++++++++ tools/libxc/xc_linux_build.c | 16 +++++-- xen/arch/ia64/xen/dom0_ops.c | 17 +++++++ xen/arch/ia64/xen/mm.c | 45 ++++++++++++++----- xen/include/asm-ia64/mm.h | 1 + xen/include/public/arch-ia64.h | 3 ++ 7 files changed, 95 insertions(+), 21 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c index 98b5982e2a..9bd507a6bf 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c @@ -497,7 +497,7 @@ xen_ia64_privcmd_entry_mmap(struct vm_area_struct* vma, unsigned long addr, struct xen_ia64_privcmd_range* privcmd_range, int i, - unsigned long mfn, + unsigned long gmfn, pgprot_t prot, domid_t domid) { @@ -506,7 +506,7 @@ xen_ia64_privcmd_entry_mmap(struct vm_area_struct* vma, unsigned long gpfn; unsigned long flags; - if ((addr & ~PAGE_MASK) != 0 || mfn == INVALID_MFN) { + if ((addr & ~PAGE_MASK) != 0 || gmfn == INVALID_MFN) { error = -EINVAL; goto out; } @@ -521,7 +521,7 @@ xen_ia64_privcmd_entry_mmap(struct vm_area_struct* vma, if (pgprot_val(prot) == PROT_READ) { flags = ASSIGN_readonly; } - error = HYPERVISOR_add_physmap(gpfn, mfn, flags, domid); + error = HYPERVISOR_add_physmap_with_gmfn(gpfn, gmfn, flags, domid); if (error != 0) { goto out; } @@ -732,7 +732,7 @@ out_enomem0: int direct_remap_pfn_range(struct vm_area_struct *vma, unsigned long address, // process virtual address - unsigned long mfn, // mfn, mfn + 1, ... mfn + size/PAGE_SIZE + unsigned long gmfn, // gmfn, gmfn + 1, ... gmfn + size/PAGE_SIZE unsigned long size, pgprot_t prot, domid_t domid) // target domain @@ -755,13 +755,13 @@ direct_remap_pfn_range(struct vm_area_struct *vma, i = (address - vma->vm_start) >> PAGE_SHIFT; for (offset = 0; offset < size; offset += PAGE_SIZE) { - error = xen_ia64_privcmd_entry_mmap(vma, (address + offset) & PAGE_MASK, privcmd_range, entry_offset + i, mfn, prot, domid); + error = xen_ia64_privcmd_entry_mmap(vma, (address + offset) & PAGE_MASK, privcmd_range, entry_offset + i, gmfn, prot, domid); if (error != 0) { break; } i++; - mfn++; + gmfn++; } return error; diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h index 4b5ea2dae0..19be0e6ed3 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h @@ -387,6 +387,28 @@ HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn, return ret; } +static inline unsigned long +__HYPERVISOR_add_physmap_with_gmfn(unsigned long gpfn, unsigned long gmfn, + unsigned long flags, domid_t domid) +{ + return _hypercall5(unsigned long, ia64_dom0vp_op, + IA64_DOM0VP_add_physmap_with_gmfn, + gpfn, gmfn, flags, domid); +} + +static inline unsigned long +HYPERVISOR_add_physmap_with_gmfn(unsigned long gpfn, unsigned long gmfn, + unsigned long flags, domid_t domid) +{ + unsigned long ret = 0; + BUG_ON(!is_running_on_xen());//XXX + if (is_running_on_xen()) { + ret = __HYPERVISOR_add_physmap_with_gmfn(gpfn, gmfn, + flags, domid); + } + return ret; +} + #ifdef CONFIG_XEN_IA64_EXPOSE_P2M static inline unsigned long HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index e3f68b6f00..dc18e58ab2 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -481,7 +481,9 @@ static int setup_guest(int xc_handle, start_info_t *start_info; unsigned long start_info_mpa; struct xen_ia64_boot_param *bp; +#if 0 // see comment below shared_info_t *shared_info; +#endif int i; DECLARE_DOMCTL; int rc; @@ -553,8 +555,8 @@ static int setup_guest(int xc_handle, (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array + start_page, &dsi); - *store_mfn = page_array[nr_pages - 2]; - *console_mfn = page_array[nr_pages - 1]; + *store_mfn = page_array[nr_pages - 2]; //XXX + *console_mfn = page_array[nr_pages - 1]; //XXX IPRINTF("start_info: 0x%lx at 0x%lx, " "store_mfn: 0x%lx at 0x%lx, " "console_mfn: 0x%lx at 0x%lx\n", @@ -593,6 +595,14 @@ static int setup_guest(int xc_handle, ctxt->user_regs.r28 = start_info_mpa + sizeof (start_info_t); munmap(start_info, PAGE_SIZE); +#if 0 + /* + * XXX FIXME: + * The follwoing initialization is done by XEN_DOMCTL_arch_setup as + * work around. + * Should XENMEM_add_to_physmap with XENMAPSPACE_shared_info be used? + */ + /* shared_info page starts its life empty. */ shared_info = xc_map_foreign_range( xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame); @@ -605,7 +615,7 @@ static int setup_guest(int xc_handle, shared_info->arch.start_info_pfn = nr_pages - 3; munmap(shared_info, PAGE_SIZE); - +#endif free(page_array); return 0; diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index affcafceaa..18c2e2f88e 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -125,6 +125,19 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) for_each_vcpu (d, v) v->arch.breakimm = d->arch.breakimm; } +#if 1 + /* + * XXX FIXME + * see comment around shared_info in setup_guest() in + * libxc/xc_linux_build.c + */ + { + int i; + d->shared_info->arch.start_info_pfn = ds->maxmem >> PAGE_SHIFT; + for_each_cpu(i) + d->shared_info->vcpu_info[i].evtchn_upcall_mask = 1; + } +#endif } } @@ -340,6 +353,10 @@ do_dom0vp_op(unsigned long cmd, ret = dom0vp_add_physmap(d, arg0, arg1, (unsigned int)arg2, (domid_t)arg3); break; + case IA64_DOM0VP_add_physmap_with_gmfn: + ret = dom0vp_add_physmap_with_gmfn(d, arg0, arg1, (unsigned int)arg2, + (domid_t)arg3); + break; case IA64_DOM0VP_expose_p2m: ret = dom0vp_expose_p2m(d, arg0, arg1, arg2, arg3); break; diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index ad26503c3e..dbf1908c18 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -1261,12 +1261,14 @@ dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, return 0; } -unsigned long -dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, - unsigned long flags, domid_t domid) +static unsigned long +__dom0vp_add_physmap(struct domain* d, unsigned long gpfn, + unsigned long mfn_or_gmfn, + unsigned long flags, domid_t domid, int is_gmfn) { - int error = 0; + int error = -EINVAL; struct domain* rd; + unsigned long mfn; /* Not allowed by a domain. */ if (flags & (ASSIGN_nocache | ASSIGN_pgc_allocated)) @@ -1283,22 +1285,26 @@ dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, break; default: gdprintk(XENLOG_INFO, "d 0x%p domid %d " - "pgfn 0x%lx mfn 0x%lx flags 0x%lx domid %d\n", - d, d->domain_id, gpfn, mfn, flags, domid); + "pgfn 0x%lx mfn_or_gmfn 0x%lx flags 0x%lx domid %d\n", + d, d->domain_id, gpfn, mfn_or_gmfn, flags, domid); return -ESRCH; } BUG_ON(rd == NULL); get_knownalive_domain(rd); } - if (unlikely(rd == d || !mfn_valid(mfn))) { - error = -EINVAL; + if (unlikely(rd == d)) goto out1; - } - if (unlikely(get_page(mfn_to_page(mfn), rd) == 0)) { - error = -EINVAL; + if (is_gmfn) { + if (domid == DOMID_XEN || domid == DOMID_IO) + goto out1; + mfn = gmfn_to_mfn(rd, mfn_or_gmfn); + } else + mfn = mfn_or_gmfn; + if (unlikely(!mfn_valid(mfn) || get_page(mfn_to_page(mfn), rd) == 0)) goto out1; - } + + error = 0; BUG_ON(page_get_owner(mfn_to_page(mfn)) == d && get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY); assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, flags); @@ -1309,6 +1315,21 @@ out1: return error; } +unsigned long +dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, + unsigned long flags, domid_t domid) +{ + return __dom0vp_add_physmap(d, gpfn, mfn, flags, domid, 0); +} + +unsigned long +dom0vp_add_physmap_with_gmfn(struct domain* d, unsigned long gpfn, + unsigned long gmfn, unsigned long flags, + domid_t domid) +{ + return __dom0vp_add_physmap(d, gpfn, gmfn, flags, domid, 1); +} + #ifdef CONFIG_XEN_IA64_EXPOSE_P2M static struct page_info* p2m_pte_zero_page = NULL; diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index c3f4b2903d..a232bd599c 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -441,6 +441,7 @@ extern unsigned long ____lookup_domain_mpa(struct domain *d, unsigned long mpadd extern unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3); extern unsigned long dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, unsigned int extent_order); extern unsigned long dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, unsigned long flags, domid_t domid); +extern unsigned long dom0vp_add_physmap_with_gmfn(struct domain* d, unsigned long gpfn, unsigned long gmfn, unsigned long flags, domid_t domid); #ifdef CONFIG_XEN_IA64_EXPOSE_P2M extern void expose_p2m_init(void); extern unsigned long dom0vp_expose_p2m(struct domain* d, unsigned long conv_start_gpfn, unsigned long assign_start_gpfn, unsigned long expose_size, unsigned long granule_pfn); diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index f3b8e423b5..d478fb0afa 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -386,6 +386,9 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); /* xen perfmon */ #define IA64_DOM0VP_perfmon 8 +/* gmfn version of IA64_DOM0VP_add_physmap */ +#define IA64_DOM0VP_add_physmap_with_gmfn 9 + // flags for page assignement to pseudo physical address space #define _ASSIGN_readonly 0 #define ASSIGN_readonly (1UL << _ASSIGN_readonly) From cd8fb13cb42085779d1200273f342e6655ca4f54 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Tue, 5 Dec 2006 13:42:37 -0700 Subject: [PATCH 192/282] [IA64] Allocate frame table/mpt table at mfn=0 Allocate frame table/mpt table at mfn=0 even when memory isn't assigned at mfn=0 as work around for transate_domain_pte(). transate_domain_pte() returns mfn=0 when the machine page isn't present as a work around for memory mapped I/O where no device is assigned. Xen might access page_info of mfn=0, so it must be guaranteed that it exists. Otherwise xen panics with a tlb miss fault in xen's virtual address area. Once transate_domain_pte() is fixed correctly, this will be removed. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/xenmem.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/xen/arch/ia64/xen/xenmem.c b/xen/arch/ia64/xen/xenmem.c index c837f0fb4b..8329ecfd6b 100644 --- a/xen/arch/ia64/xen/xenmem.c +++ b/xen/arch/ia64/xen/xenmem.c @@ -181,6 +181,23 @@ void init_virtual_frametable(void) printk("virtual machine to physical table: %p size: %lukB\n" "max_page: 0x%lx\n", mpt_table, ((table_size << PAGE_SHIFT) >> 10), max_page); + + /* + * XXX work around for translate_domain_pte(). + * It returns mfn=0 when the machine page isn't present. This + * behavior is a work around for memory mapped I/O where no device + * is assigned. Xen might access page_info of mfn=0, so it must + * be guaranteed that it exists. Otherwise xen panics with tlb miss + * fault in xen's virtual address area. + * + * Once translate_domain_pte() is fixed correctly, this will + * be removed. + */ + if (!mfn_valid(0)) { + printk("allocating frame table/mpt table at mfn 0.\n"); + create_frametable_page_table(0, PAGE_SIZE, NULL); + create_mpttable_page_table(0, PAGE_SIZE, NULL); + } } int From 75890339a9a6fa2a8f04670b495f77e9ddfa2203 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Wed, 6 Dec 2006 02:34:46 -0700 Subject: [PATCH 193/282] [IA64] Fix Vti Use new foreign page mapping interface Signed-off-by: Xu Anthony Signed-off-by: Zhang Xiantao Signed-off-by: Zhang Xin --- tools/ioemu/vl.c | 32 +++++++++++----------------- tools/libxc/ia64/xc_ia64_hvm_build.c | 25 ++++------------------ 2 files changed, 16 insertions(+), 41 deletions(-) diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index a2700ef313..2b92cbbc70 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -6378,6 +6378,10 @@ int main(int argc, char **argv) } #if defined (__ia64__) + /* ram_size passed from xend has added on GFW memory, + so we must subtract it here */ + ram_size -= 16 * MEM_M; + if (ram_size > MMIO_START) ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */ #endif @@ -6443,36 +6447,24 @@ int main(int argc, char **argv) free(page_array); #elif defined(__ia64__) - - if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, - IO_PAGE_START >> PAGE_SHIFT, 3) != 3) { - fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); - exit(-1); - } shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ|PROT_WRITE, - page_array[0]); - - fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n", - IO_PAGE_START >> PAGE_SHIFT, page_array[0]); + IO_PAGE_START >> PAGE_SHIFT); buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, PROT_READ|PROT_WRITE, - page_array[2]); - fprintf(logfile, "Buffered IO page at pfn:%lx, mfn: %016lx\n", - BUFFER_IO_PAGE_START >> PAGE_SHIFT, page_array[2]); - - if (xc_ia64_get_pfn_list(xc_handle, domid, - page_array, 0, nr_pages) != nr_pages) { - fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); - exit(-1); - } + BUFFER_IO_PAGE_START >> PAGE_SHIFT); + for (i = 0; i < tmp_nr_pages; i++) + page_array[i] = i; + + /* VTI will not use memory between 3G~4G, so we just pass a legal pfn + to make QEMU map continuous virtual memory space */ if (ram_size > MMIO_START) { for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++) page_array[(MMIO_START >> PAGE_SHIFT) + i] = - page_array[(IO_PAGE_START >> PAGE_SHIFT) + 1]; + (STORE_PAGE_START >> PAGE_SHIFT); } phys_ram_base = xc_map_foreign_batch(xc_handle, domid, diff --git a/tools/libxc/ia64/xc_ia64_hvm_build.c b/tools/libxc/ia64/xc_ia64_hvm_build.c index a38728d73a..ac3a2ff00d 100644 --- a/tools/libxc/ia64/xc_ia64_hvm_build.c +++ b/tools/libxc/ia64/xc_ia64_hvm_build.c @@ -13,32 +13,15 @@ xc_ia64_copy_to_domain_pages(int xc_handle, uint32_t domid, void* src_page, unsigned long dst_pfn, int nr_pages) { // N.B. gva should be page aligned - - xen_pfn_t *page_array = NULL; int i; - page_array = malloc(nr_pages * sizeof(xen_pfn_t)); - if (page_array == NULL) { - PERROR("Could not allocate memory"); - goto error_out; - } - if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, - dst_pfn, nr_pages) != nr_pages) { - PERROR("Could not get the page frame list"); - goto error_out; - } - for (i = 0; i < nr_pages; i++) { - if (xc_copy_to_domain_page(xc_handle, domid, page_array[i], + if (xc_copy_to_domain_page(xc_handle, domid, dst_pfn + i, src_page + (i << PAGE_SHIFT))) - goto error_out; + return -1; } - free(page_array); - return 0; -error_out: - free(page_array); - return -1; + return 0; } int @@ -657,7 +640,7 @@ setup_guest(int xc_handle, uint32_t dom, unsigned long memsize, rc = xc_domain_memory_populate_physmap(xc_handle, dom, 3, 0, 0, &pfn_list[nr_pages - 3]); if (rc != 0) { - PERROR("Could not allocate GFW memory for Vti guest.\n"); + PERROR("Could not allocate IO page or store page or buffer io page.\n"); goto error_out; } From 6e66f078d444f2f49450bb957ae4245cf296626a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 10:10:06 +0000 Subject: [PATCH 194/282] Fix HTTP server. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvServer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 6bfff3a318..95453d7b46 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -165,7 +165,7 @@ class XendServers: else: break -def _loadConfig(servers): +def _loadConfig(servers, root): if xroot.get_xend_http_server(): servers.add(HttpServer(root, xroot.get_xend_address(), @@ -219,5 +219,5 @@ def create(): root = SrvDir() root.putChild('xend', SrvRoot()) servers = XendServers() - _loadConfig(servers) + _loadConfig(servers, root) return servers From 1d68773ad2199a0b5dfac08f8cdc54a95a0611ae Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 10:12:39 +0000 Subject: [PATCH 195/282] Move the actual call routed by do_legacy_api_with_uuid out of the scope of the domains_lock. The call itself is already locking as necessary, and it is important for domain_start to be able to release the lock across the scope of waitForDevices. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendDomain.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index cc3c5c783e..4b11634403 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -641,17 +641,22 @@ class XendDomain: return (self.get_vm_with_dev_uuid(klass, dev_uuid) != None) def do_legacy_api_with_uuid(self, fn, vm_uuid, *args, **kwargs): + dom = self.uuid_to_dom(vm_uuid) + fn(dom, *args, **kwargs) + + def uuid_to_dom(self, vm_uuid): self.domains_lock.acquire() try: for domid, dom in self.domains.items(): - if dom.get_uuid == vm_uuid: - return fn(domid, *args, **kwargs) + if dom.get_uuid() == vm_uuid: + return domid if vm_uuid in self.managed_domains: domid = self.managed_domains[vm_uuid].getDomid() - if domid == None: - domid = self.managed_domains[vm_uuid].getName() - return fn(domid, *args, **kwargs) + if domid is None: + return self.managed_domains[vm_uuid].getName() + else: + return domid raise XendInvalidDomain("Domain does not exist") finally: From 81f605d9cbcedb8494a6da10b442b42f4bfe6c6d Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 10:13:46 +0000 Subject: [PATCH 196/282] Don't trace inside SrvServer.py -- it's doing a one-second sleep in a loop, so it just fills the trace with useless clutter. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvDaemon.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py index 155062a704..bd93e6fc56 100644 --- a/tools/python/xen/xend/server/SrvDaemon.py +++ b/tools/python/xen/xend/server/SrvDaemon.py @@ -278,6 +278,8 @@ class Daemon: modulename = m.group(1) if re.search('sxp.py', modulename): return None + if re.search('SrvServer.py', modulename): + return None self.traceindent += 1 self.print_trace("> %s:%s\n" % (modulename, code.co_name)) From 5ef203e373b2f0380848f63b1d63d817d4301f0f Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 10:37:10 +0000 Subject: [PATCH 197/282] Fix server reloading when the HTTP server is enabled. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvServer.py | 24 ++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tools/python/xen/xend/server/SrvServer.py b/tools/python/xen/xend/server/SrvServer.py index 95453d7b46..4dfe8584e0 100644 --- a/tools/python/xen/xend/server/SrvServer.py +++ b/tools/python/xen/xend/server/SrvServer.py @@ -62,8 +62,9 @@ xroot = XendRoot.instance() class XendServers: - def __init__(self): + def __init__(self, root): self.servers = [] + self.root = root self.cleaningUp = False self.reloadingConfig = False @@ -101,6 +102,9 @@ class XendServers: while True: threads = [] for server in self.servers: + if server.ready: + continue + thread = Thread(target=server.run, name=server.__class__.__name__) if isinstance(server, HttpServer): thread.setDaemon(True) @@ -156,21 +160,23 @@ class XendServers: pass if self.reloadingConfig: - log.info("Restarting all servers...") + log.info("Restarting all XML-RPC and Xen-API servers...") self.cleaningUp = False self.reloadingConfig = False xroot.set_config() - self.servers = [] - _loadConfig(self) + new_servers = [x for x in self.servers + if isinstance(x, HttpServer)] + self.servers = new_servers + _loadConfig(self, self.root, True) else: break -def _loadConfig(servers, root): - if xroot.get_xend_http_server(): +def _loadConfig(servers, root, reload): + if not reload and xroot.get_xend_http_server(): servers.add(HttpServer(root, xroot.get_xend_address(), xroot.get_xend_port())) - if xroot.get_xend_unix_server(): + if not reload and xroot.get_xend_unix_server(): path = xroot.get_xend_unix_path() log.info('unix path=' + path) servers.add(UnixHttpServer(root, path)) @@ -218,6 +224,6 @@ def _loadConfig(servers, root): def create(): root = SrvDir() root.putChild('xend', SrvRoot()) - servers = XendServers() - _loadConfig(servers, root) + servers = XendServers(root) + _loadConfig(servers, root, False) return servers From 6455e182f2cd18f7e21cf55a9a986b206a9b4549 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 10:47:31 +0000 Subject: [PATCH 198/282] Added server proxy and session manager for Xen-API clients. Signed-off-by: Ewan Mellor --- tools/python/xen/xm/XenAPI.py | 132 ++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 tools/python/xen/xm/XenAPI.py diff --git a/tools/python/xen/xm/XenAPI.py b/tools/python/xen/xm/XenAPI.py new file mode 100644 index 0000000000..7d469fc997 --- /dev/null +++ b/tools/python/xen/xm/XenAPI.py @@ -0,0 +1,132 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2006 XenSource Inc. +#============================================================================ +# +# Parts of this file are based upon xmlrpclib.py, the XML-RPC client +# interface included in the Python distribution. +# +# Copyright (c) 1999-2002 by Secret Labs AB +# Copyright (c) 1999-2002 by Fredrik Lundh +# +# By obtaining, using, and/or copying this software and/or its +# associated documentation, you agree that you have read, understood, +# and will comply with the following terms and conditions: +# +# Permission to use, copy, modify, and distribute this software and +# its associated documentation for any purpose and without fee is +# hereby granted, provided that the above copyright notice appears in +# all copies, and that both that copyright notice and this permission +# notice appear in supporting documentation, and that the name of +# Secret Labs AB or the author not be used in advertising or publicity +# pertaining to distribution of the software without specific, written +# prior permission. +# +# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD +# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- +# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR +# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# -------------------------------------------------------------------- + +import xmlrpclib + +import xen.util.xmlrpclib2 + + +class Failure(Exception): + def __init__(self, details): + self.details = details + + def __str__(self): + return "Xen-API failure: %s" % str(self.details) + + +class Session(xen.util.xmlrpclib2.ServerProxy): + """A server proxy and session manager for communicating with Xend using + the Xen-API. + + Example: + + session = Session('http://localhost:9363/') + session.login_with_password('me', 'mypassword') + session.xenapi.VM.start(vm_uuid) + session.xenapi.session.logout() + + For now, this class also supports the legacy XML-RPC API, using + session.xend.domain('Domain-0') and similar. This support will disappear + once there is a working Xen-API replacement for every call in the legacy + API. + """ + + def __init__(self, uri, transport=None, encoding=None, verbose=0, + allow_none=1): + xen.util.xmlrpclib2.ServerProxy.__init__(self, uri, transport, + encoding, verbose, + allow_none) + self._session = None + + + def _xen_request(self, methodname, params): + full_params = (self._session,) + params + return _parse_result(getattr(self, methodname)(*full_params)) + + + def _login(self, method, username, password): + self._session = _parse_result( + getattr(self, 'session.%s' % method)(username, password)) + + + def __getattr__(self, name): + if name == 'xenapi': + return _Dispatcher(self._xen_request, None) + elif name.startswith('login'): + return lambda u, p: self._login(name, u, p) + else: + return xen.util.xmlrpclib2.ServerProxy.__getattr__(self, name) + + +def _parse_result(result): + if 'Status' not in result: + raise xmlrpclib.Fault(500, 'Missing Status in response from server') + if result['Status'] == 'Success': + if 'Value' in result: + return result['Value'] + else: + raise xmlrpclib.Fault(500, + 'Missing Value in response from server') + else: + if 'ErrorDescription' in result: + raise Failure(result['ErrorDescription']) + else: + raise xmlrpclib.Fault( + 500, 'Missing ErrorDescription in response from server') + + +# Based upon _Method from xmlrpclib. +class _Dispatcher: + def __init__(self, send, name): + self.__send = send + self.__name = name + def __getattr__(self, name): + if self.__name is None: + return _Dispatcher(self.__send, name) + else: + return _Dispatcher(self.__send, "%s.%s" % (self.__name, name)) + def __call__(self, *args): + return self.__send(self.__name, args) From 8edc7b1c06a06f9291f359500805251609613eb9 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 11:02:32 +0000 Subject: [PATCH 199/282] Added support for configuration file for xm, and use that to specify contact and authentication details for the Xen-API server. The default behaviour is still to use the existing legacy XML-RPC server. Signed-off-by: Ewan Mellor --- tools/examples/xm-config.xml | 43 ++++++++++++++++ tools/python/xen/xm/create.py | 2 +- tools/python/xen/xm/main.py | 89 +++++++++++++++++++++++++++++++-- tools/python/xen/xm/migrate.py | 3 +- tools/python/xen/xm/new.py | 5 +- tools/python/xen/xm/shutdown.py | 4 +- 6 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 tools/examples/xm-config.xml diff --git a/tools/examples/xm-config.xml b/tools/examples/xm-config.xml new file mode 100644 index 0000000000..dbd8778bae --- /dev/null +++ b/tools/examples/xm-config.xml @@ -0,0 +1,43 @@ + + + + + + + + diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 8b5301b9e8..c081560f8e 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -29,13 +29,13 @@ import xmlrpclib from xen.xend import sxp from xen.xend import PrettyPrint import xen.xend.XendClient -from xen.xend.XendClient import server from xen.xend.XendBootloader import bootloader from xen.util import blkif from xen.util import security from xen.xm.opts import * +from main import server import console diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 9982dc3388..4a545cb9a6 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -21,6 +21,7 @@ """Grand unified management application for Xen. """ +import atexit import os import sys import re @@ -31,6 +32,7 @@ import xmlrpclib import traceback import datetime from select import select +import xml.dom.minidom import warnings warnings.filterwarnings('ignore', category=FutureWarning) @@ -38,12 +40,14 @@ warnings.filterwarnings('ignore', category=FutureWarning) from xen.xend import PrettyPrint from xen.xend import sxp from xen.xend import XendClient -from xen.xend.XendClient import server from xen.xend.XendConstants import * from xen.xm.opts import OptionError, Opts, wrap, set_true from xen.xm import console from xen.util import security +from xen.util.xmlrpclib2 import ServerProxy + +import XenAPI # getopt.gnu_getopt is better, but only exists in Python 2.3+. Use # getopt.getopt if gnu_getopt is not available. This will mean that options @@ -51,6 +55,12 @@ from xen.util import security if not hasattr(getopt, 'gnu_getopt'): getopt.gnu_getopt = getopt.getopt +XM_CONFIG_FILE = '/etc/xen/xm-config.xml' + +# Supported types of server +SERVER_LEGACY_XMLRPC = 'LegacyXMLRPC' +SERVER_XEN_API = 'Xen-API' + # General help message USAGE_HELP = "Usage: xm [args]\n\n" \ @@ -319,6 +329,35 @@ acm_commands = [ all_commands = (domain_commands + host_commands + scheduler_commands + device_commands + vnet_commands + acm_commands) + +## +# Configuration File Parsing +## + +if os.path.isfile(XM_CONFIG_FILE): + config = xml.dom.minidom.parse(XM_CONFIG_FILE) +else: + config = None + +def parseServer(): + if config: + server = config.getElementsByTagName('server') + if server: + st = server[0].getAttribute('type') + if st != SERVER_XEN_API: + st = SERVER_LEGACY_XMLRPC + return (st, server[0].getAttribute('uri')) + + return SERVER_LEGACY_XMLRPC, XendClient.uri + +def parseAuthentication(): + server = config.getElementsByTagName('server')[0] + return (server.getAttribute('username'), + server.getAttribute('password')) + +serverType, serverURI = parseServer() + + #################################################################### # # Help/usage printing functions @@ -469,6 +508,16 @@ def err(msg): print >>sys.stderr, "Error:", msg +def get_single_vm(dom): + uuids = server.xenapi.VM.get_by_name_label(dom) + n = len(uuids) + if n == 1: + return uuids[0] + else: + dominfo = server.xend.domain(dom, False) + return dominfo['uuid'] + + ######################################################################### # # Main xm functions @@ -767,17 +816,26 @@ def xm_start(args): sys.exit(1) dom = params[0] - server.xend.domain.start(dom, paused) + if serverType == SERVER_XEN_API: + server.xenapi.VM.start(get_single_vm(dom), paused) + else: + server.xend.domain.start(dom, paused) def xm_delete(args): arg_check(args, "delete", 1) dom = args[0] - server.xend.domain.delete(dom) + if serverType == SERVER_XEN_API: + server.xenapi.VM.destroy(dom) + else: + server.xend.domain.delete(dom) def xm_suspend(args): arg_check(args, "suspend", 1) dom = args[0] - server.xend.domain.suspend(dom) + if serverType == SERVER_XEN_API: + server.xenapi.VM.suspend(get_single_vm(dom)) + else: + server.xend.domain.suspend(dom) def xm_resume(args): arg_check(args, "resume", 1, 2) @@ -799,7 +857,10 @@ def xm_resume(args): sys.exit(1) dom = params[0] - server.xend.domain.resume(dom, paused) + if serverType == SERVER_XEN_API: + server.xenapi.VM.resume(dom, paused) + else: + server.xend.domain.resume(dom, paused) def xm_reboot(args): arg_check(args, "reboot", 1, 3) @@ -1577,6 +1638,8 @@ def deprecated(old,new): "Command %s is deprecated. Please use xm %s instead." % (old, new)) def main(argv=sys.argv): + global server + if len(argv) < 2: usage() @@ -1595,6 +1658,19 @@ def main(argv=sys.argv): args = argv[2:] if cmd: try: + if serverType == SERVER_XEN_API: + server = XenAPI.Session(serverURI) + username, password = parseAuthentication() + server.login_with_password(username, password) + def logout(): + try: + server.xenapi.session.logout() + except: + pass + atexit.register(logout) + else: + server = ServerProxy(serverURI) + rc = cmd(args) if rc: usage() @@ -1615,6 +1691,9 @@ def main(argv=sys.argv): sys.exit(1) except SystemExit: sys.exit(1) + except XenAPI.Failure, exn: + err(str(exn)) + sys.exit(1) except xmlrpclib.Fault, ex: if ex.faultCode == XendClient.ERROR_INVALID_DOMAIN: err("Domain '%s' does not exist." % ex.faultString) diff --git a/tools/python/xen/xm/migrate.py b/tools/python/xen/xm/migrate.py index b362ae9057..72aca71932 100644 --- a/tools/python/xen/xm/migrate.py +++ b/tools/python/xen/xm/migrate.py @@ -21,9 +21,10 @@ import sys -from xen.xend.XendClient import server from xen.xm.opts import * +from main import server + gopts = Opts(use="""[options] DOM HOST Migrate domain DOM to host HOST. diff --git a/tools/python/xen/xm/new.py b/tools/python/xen/xm/new.py index 7af65510a9..2c6cae84b6 100644 --- a/tools/python/xen/xm/new.py +++ b/tools/python/xen/xm/new.py @@ -21,10 +21,9 @@ import xmlrpclib from xen.xend import PrettyPrint from xen.xend import sxp from xen.xend import XendClient -from xen.xend.XendClient import server -from xen.xm.opts import * -from xen.xm.create import * +from opts import * +from create import * def make_unstarted_domain(opts, config): """Create an unstarted domain. diff --git a/tools/python/xen/xm/shutdown.py b/tools/python/xen/xm/shutdown.py index a63c3523ca..b5542d9611 100644 --- a/tools/python/xen/xm/shutdown.py +++ b/tools/python/xen/xm/shutdown.py @@ -19,9 +19,9 @@ """ import time -from xen.xend.XendClient import server from xen.xend import sxp -from xen.xm.opts import * +from opts import * +from main import server gopts = Opts(use="""[options] [DOM] From 2420eb41c59500b35ccca9af5520cad65b3389f8 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 11:24:37 +0000 Subject: [PATCH 200/282] Implement VM.set_name_label. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/XendAPI.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 9f3b2ed459..0b4e35b8ce 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -821,8 +821,9 @@ class XendAPI: dom = XendDomain.instance().get_vm_by_uuid(vm_ref) return xen_api_todo() - def VM_set_name_label(self, session, vm_ref): + def VM_set_name_label(self, session, vm_ref, label): dom = XendDomain.instance().get_vm_by_uuid(vm_ref) + dom.setName(label) return xen_api_success_void() def VM_set_name_description(self, session, vm_ref): From 556d54c7ce8d0ed4a3bf78960c697b53d1c54794 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 11:25:51 +0000 Subject: [PATCH 201/282] Added Xen-API implementations for xm pause, xm unpause, xm destroy, xm rename, and fix xm suspend and xm delete. Signed-off-by: Ewan Mellor --- tools/python/xen/xm/main.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 4a545cb9a6..95cbda9033 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -825,7 +825,7 @@ def xm_delete(args): arg_check(args, "delete", 1) dom = args[0] if serverType == SERVER_XEN_API: - server.xenapi.VM.destroy(dom) + server.xenapi.VM.destroy(get_single_vm(dom)) else: server.xend.domain.delete(dom) @@ -858,7 +858,7 @@ def xm_resume(args): dom = params[0] if serverType == SERVER_XEN_API: - server.xenapi.VM.resume(dom, paused) + server.xenapi.VM.resume(get_single_vm(dom), paused) else: server.xend.domain.resume(dom, paused) @@ -876,13 +876,19 @@ def xm_pause(args): arg_check(args, "pause", 1) dom = args[0] - server.xend.domain.pause(dom) + if serverType == SERVER_XEN_API: + server.xenapi.VM.pause(get_single_vm(dom)) + else: + server.xend.domain.pause(dom) def xm_unpause(args): arg_check(args, "unpause", 1) dom = args[0] - server.xend.domain.unpause(dom) + if serverType == SERVER_XEN_API: + server.xenapi.VM.unpause(get_single_vm(dom)) + else: + server.xend.domain.unpause(dom) def xm_dump_core(args): live = False @@ -923,7 +929,10 @@ def xm_dump_core(args): def xm_rename(args): arg_check(args, "rename", 2) - server.xend.domain.setName(args[0], args[1]) + if serverType == SERVER_XEN_API: + server.xenapi.VM.set_name_label(get_single_vm(args[0]), args[1]) + else: + server.xend.domain.setName(args[0], args[1]) def xm_importcommand(command, args): cmd = __import__(command, globals(), locals(), 'xen.xm') @@ -981,7 +990,12 @@ def xm_vcpu_set(args): def xm_destroy(args): arg_check(args, "destroy", 1) - server.xend.domain.destroy(args[0]) + + dom = args[0] + if serverType == SERVER_XEN_API: + server.xenapi.VM.hard_shutdown(get_single_vm(dom)) + else: + server.xend.domain.destroy(dom) def xm_domid(args): From f1717b30d4f0061487c82b417991e94708a852dd Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Wed, 6 Dec 2006 12:13:22 +0000 Subject: [PATCH 202/282] [XEN] remove unused monitor_vtable mapping. Signed-off-by: Tim Deegan --- xen/arch/x86/mm/shadow/common.c | 8 +++----- xen/include/asm-x86/domain.h | 1 - 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 881f91a81d..d554896e83 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -2433,11 +2433,10 @@ void sh_update_paging_modes(struct vcpu *v) } } - if ( pagetable_get_pfn(v->arch.monitor_table) == 0 ) + if ( pagetable_is_null(v->arch.monitor_table) ) { mfn_t mmfn = shadow_make_monitor_table(v); v->arch.monitor_table = pagetable_from_mfn(mmfn); - v->arch.monitor_vtable = sh_map_domain_page(mmfn); } if ( v->arch.shadow.mode != old_mode ) @@ -2467,12 +2466,10 @@ void sh_update_paging_modes(struct vcpu *v) return; } - sh_unmap_domain_page(v->arch.monitor_vtable); old_mfn = pagetable_get_mfn(v->arch.monitor_table); v->arch.monitor_table = pagetable_null(); new_mfn = v->arch.shadow.mode->make_monitor_table(v); v->arch.monitor_table = pagetable_from_mfn(new_mfn); - v->arch.monitor_vtable = sh_map_domain_page(new_mfn); SHADOW_PRINTK("new monitor table %"SH_PRI_mfn "\n", mfn_x(new_mfn)); @@ -3272,7 +3269,8 @@ void shadow_audit_p2m(struct domain *d) //SHADOW_PRINTK("p2m audit starts\n"); - test_linear = ( (d == current->domain) && current->arch.monitor_vtable ); + test_linear = ( (d == current->domain) + && !pagetable_is_null(current->arch.monitor_table) ); if ( test_linear ) local_flush_tlb(); diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index a7b511fc32..20793910ba 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -196,7 +196,6 @@ struct arch_vcpu unsigned long cr3; /* (MA) value to install in HW CR3 */ void *guest_vtable; /* virtual addr of pagetable */ - root_pgentry_t *monitor_vtable; /* virtual addr of monitor_table */ /* Current LDT details. */ unsigned long shadow_ldt_mapcnt; From 3f4a3b36025877a71b55fdf800d0486d8642b0c5 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 13:24:28 +0000 Subject: [PATCH 203/282] Tidy-up some of the descriptions. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 374 +++++++++++++++--------------- 1 file changed, 187 insertions(+), 187 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 81cd8828d4..de023012ac 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -23,7 +23,7 @@ The following classes are defined: Name & Description \\ \hline {\tt session} & A session \\ -{\tt task} & A longrunning asynchronous task \\ +{\tt task} & A long-running asynchronous task \\ {\tt VM} & A virtual machine (or 'guest') \\ {\tt host} & A physical host \\ {\tt host\_cpu} & A physical CPU \\ @@ -336,7 +336,7 @@ void \subsubsection{RPC name:~get\_this\_host} {\bf Overview:} -get accessor message derived from field this\_host of object session +Get the this\_host field of the given session. \noindent {\bf Signature:} \begin{verbatim} (host ref) get_this_host (session_id s, session ref self)\end{verbatim} @@ -368,7 +368,7 @@ value of the field \subsubsection{RPC name:~get\_this\_user} {\bf Overview:} -get accessor message derived from field this\_user of object session +Get the this\_user field of the given session. \noindent {\bf Signature:} \begin{verbatim} (user ref) get_this_user (session_id s, session ref self)\end{verbatim} @@ -533,7 +533,7 @@ all fields from the object \begin{longtable}{|lllp{0.38\textwidth}|} \hline \multicolumn{1}{|l}{Name} & \multicolumn{3}{l|}{\bf task} \\ -\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A longrunning asynchronous task}} \\ +\multicolumn{1}{|l}{Description} & \multicolumn{3}{l|}{\parbox{11cm}{\em A long-running asynchronous task}} \\ \hline Quals & Field & Type & Description \\ \hline @@ -602,7 +602,7 @@ return the user's running tasks. \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object task +Get the uuid field of the given task. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, task ref self)\end{verbatim} @@ -634,7 +634,7 @@ value of the field \subsubsection{RPC name:~get\_name\_label} {\bf Overview:} -get accessor message derived from field name/label of object task +Get the name/label field of the given task. \noindent {\bf Signature:} \begin{verbatim} string get_name_label (session_id s, task ref self)\end{verbatim} @@ -666,7 +666,7 @@ value of the field \subsubsection{RPC name:~set\_name\_label} {\bf Overview:} -set accessor message derived from field name/label of object task +Set the name/label field of the given task. \noindent {\bf Signature:} \begin{verbatim} void set_name_label (session_id s, task ref self, string value)\end{verbatim} @@ -700,7 +700,7 @@ void \subsubsection{RPC name:~get\_name\_description} {\bf Overview:} -get accessor message derived from field name/description of object task +Get the name/description field of the given task. \noindent {\bf Signature:} \begin{verbatim} string get_name_description (session_id s, task ref self)\end{verbatim} @@ -732,7 +732,7 @@ value of the field \subsubsection{RPC name:~set\_name\_description} {\bf Overview:} -set accessor message derived from field name/description of object task +Set the name/description field of the given task. \noindent {\bf Signature:} \begin{verbatim} void set_name_description (session_id s, task ref self, string value)\end{verbatim} @@ -1335,7 +1335,7 @@ A list of all the IDs of all the VMs \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object VM +Get the uuid field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, VM ref self)\end{verbatim} @@ -1367,7 +1367,7 @@ value of the field \subsubsection{RPC name:~get\_power\_state} {\bf Overview:} -get accessor message derived from field power\_state of object VM +Get the power\_state field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (vm_power_state) get_power_state (session_id s, VM ref self)\end{verbatim} @@ -1399,7 +1399,7 @@ value of the field \subsubsection{RPC name:~get\_name\_label} {\bf Overview:} -get accessor message derived from field name/label of object VM +Get the name/label field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_name_label (session_id s, VM ref self)\end{verbatim} @@ -1431,7 +1431,7 @@ value of the field \subsubsection{RPC name:~set\_name\_label} {\bf Overview:} -set accessor message derived from field name/label of object VM +Set the name/label field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_name_label (session_id s, VM ref self, string value)\end{verbatim} @@ -1465,7 +1465,7 @@ void \subsubsection{RPC name:~get\_name\_description} {\bf Overview:} -get accessor message derived from field name/description of object VM +Get the name/description field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_name_description (session_id s, VM ref self)\end{verbatim} @@ -1497,7 +1497,7 @@ value of the field \subsubsection{RPC name:~set\_name\_description} {\bf Overview:} -set accessor message derived from field name/description of object VM +Set the name/description field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_name_description (session_id s, VM ref self, string value)\end{verbatim} @@ -1531,7 +1531,7 @@ void \subsubsection{RPC name:~get\_user\_version} {\bf Overview:} -get accessor message derived from field user\_version of object VM +Get the user\_version field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_user_version (session_id s, VM ref self)\end{verbatim} @@ -1563,7 +1563,7 @@ value of the field \subsubsection{RPC name:~set\_user\_version} {\bf Overview:} -set accessor message derived from field user\_version of object VM +Set the user\_version field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_user_version (session_id s, VM ref self, int value)\end{verbatim} @@ -1597,7 +1597,7 @@ void \subsubsection{RPC name:~get\_is\_a\_template} {\bf Overview:} -get accessor message derived from field is\_a\_template of object VM +Get the is\_a\_template field of the given VM. \noindent {\bf Signature:} \begin{verbatim} bool get_is_a_template (session_id s, VM ref self)\end{verbatim} @@ -1629,7 +1629,7 @@ value of the field \subsubsection{RPC name:~set\_is\_a\_template} {\bf Overview:} -set accessor message derived from field is\_a\_template of object VM +Set the is\_a\_template field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_is_a_template (session_id s, VM ref self, bool value)\end{verbatim} @@ -1663,7 +1663,7 @@ void \subsubsection{RPC name:~get\_resident\_on} {\bf Overview:} -get accessor message derived from field resident\_on of object VM +Get the resident\_on field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (host ref) get_resident_on (session_id s, VM ref self)\end{verbatim} @@ -1695,7 +1695,7 @@ value of the field \subsubsection{RPC name:~get\_memory\_static\_max} {\bf Overview:} -get accessor message derived from field memory/static\_max of object VM +Get the memory/static\_max field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_memory_static_max (session_id s, VM ref self)\end{verbatim} @@ -1727,7 +1727,7 @@ value of the field \subsubsection{RPC name:~get\_memory\_dynamic\_max} {\bf Overview:} -get accessor message derived from field memory/dynamic\_max of object VM +Get the memory/dynamic\_max field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_memory_dynamic_max (session_id s, VM ref self)\end{verbatim} @@ -1759,7 +1759,7 @@ value of the field \subsubsection{RPC name:~set\_memory\_dynamic\_max} {\bf Overview:} -set accessor message derived from field memory/dynamic\_max of object VM +Set the memory/dynamic\_max field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_memory_dynamic_max (session_id s, VM ref self, int value)\end{verbatim} @@ -1793,7 +1793,7 @@ void \subsubsection{RPC name:~get\_memory\_actual} {\bf Overview:} -get accessor message derived from field memory/actual of object VM +Get the memory/actual field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_memory_actual (session_id s, VM ref self)\end{verbatim} @@ -1825,7 +1825,7 @@ value of the field \subsubsection{RPC name:~get\_memory\_dynamic\_min} {\bf Overview:} -get accessor message derived from field memory/dynamic\_min of object VM +Get the memory/dynamic\_min field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_memory_dynamic_min (session_id s, VM ref self)\end{verbatim} @@ -1857,7 +1857,7 @@ value of the field \subsubsection{RPC name:~set\_memory\_dynamic\_min} {\bf Overview:} -set accessor message derived from field memory/dynamic\_min of object VM +Set the memory/dynamic\_min field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_memory_dynamic_min (session_id s, VM ref self, int value)\end{verbatim} @@ -1891,7 +1891,7 @@ void \subsubsection{RPC name:~get\_memory\_static\_min} {\bf Overview:} -get accessor message derived from field memory/static\_min of object VM +Get the memory/static\_min field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_memory_static_min (session_id s, VM ref self)\end{verbatim} @@ -1923,7 +1923,7 @@ value of the field \subsubsection{RPC name:~get\_VCPUs\_policy} {\bf Overview:} -get accessor message derived from field VCPUs/policy of object VM +Get the VCPUs/policy field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_VCPUs_policy (session_id s, VM ref self)\end{verbatim} @@ -1955,7 +1955,7 @@ value of the field \subsubsection{RPC name:~set\_VCPUs\_policy} {\bf Overview:} -set accessor message derived from field VCPUs/policy of object VM +Set the VCPUs/policy field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_VCPUs_policy (session_id s, VM ref self, string value)\end{verbatim} @@ -1989,7 +1989,7 @@ void \subsubsection{RPC name:~get\_VCPUs\_params} {\bf Overview:} -get accessor message derived from field VCPUs/params of object VM +Get the VCPUs/params field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_VCPUs_params (session_id s, VM ref self)\end{verbatim} @@ -2021,7 +2021,7 @@ value of the field \subsubsection{RPC name:~set\_VCPUs\_params} {\bf Overview:} -set accessor message derived from field VCPUs/params of object VM +Set the VCPUs/params field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_VCPUs_params (session_id s, VM ref self, string value)\end{verbatim} @@ -2055,7 +2055,7 @@ void \subsubsection{RPC name:~get\_VCPUs\_number} {\bf Overview:} -get accessor message derived from field VCPUs/number of object VM +Get the VCPUs/number field of the given VM. \noindent {\bf Signature:} \begin{verbatim} int get_VCPUs_number (session_id s, VM ref self)\end{verbatim} @@ -2087,7 +2087,7 @@ value of the field \subsubsection{RPC name:~get\_VCPUs\_utilisation} {\bf Overview:} -get accessor message derived from field VCPUs/utilisation of object VM +Get the VCPUs/utilisation field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((int -> float) Map) get_VCPUs_utilisation (session_id s, VM ref self)\end{verbatim} @@ -2119,7 +2119,7 @@ value of the field \subsubsection{RPC name:~get\_VCPUs\_features\_required} {\bf Overview:} -get accessor message derived from field VCPUs/features/required of object VM +Get the VCPUs/features/required field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_required (session_id s, VM ref self)\end{verbatim} @@ -2151,7 +2151,7 @@ value of the field \subsubsection{RPC name:~get\_VCPUs\_features\_can\_use} {\bf Overview:} -get accessor message derived from field VCPUs/features/can\_use of object VM +Get the VCPUs/features/can\_use field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_can_use (session_id s, VM ref self)\end{verbatim} @@ -2183,7 +2183,7 @@ value of the field \subsubsection{RPC name:~get\_VCPUs\_features\_force\_on} {\bf Overview:} -get accessor message derived from field VCPUs/features/force\_on of object VM +Get the VCPUs/features/force\_on field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_force_on (session_id s, VM ref self)\end{verbatim} @@ -2283,7 +2283,7 @@ void \subsubsection{RPC name:~get\_VCPUs\_features\_force\_off} {\bf Overview:} -get accessor message derived from field VCPUs/features/force\_off of object VM +Get the VCPUs/features/force\_off field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((cpu_feature) Set) get_VCPUs_features_force_off (session_id s, VM ref self)\end{verbatim} @@ -2383,7 +2383,7 @@ void \subsubsection{RPC name:~get\_actions\_after\_shutdown} {\bf Overview:} -get accessor message derived from field actions/after\_shutdown of object VM +Get the actions/after\_shutdown field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (on_normal_exit) get_actions_after_shutdown (session_id s, VM ref self)\end{verbatim} @@ -2415,7 +2415,7 @@ value of the field \subsubsection{RPC name:~set\_actions\_after\_shutdown} {\bf Overview:} -set accessor message derived from field actions/after\_shutdown of object VM +Set the actions/after\_shutdown field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_actions_after_shutdown (session_id s, VM ref self, on_normal_exit value)\end{verbatim} @@ -2449,7 +2449,7 @@ void \subsubsection{RPC name:~get\_actions\_after\_reboot} {\bf Overview:} -get accessor message derived from field actions/after\_reboot of object VM +Get the actions/after\_reboot field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (on_normal_exit) get_actions_after_reboot (session_id s, VM ref self)\end{verbatim} @@ -2481,7 +2481,7 @@ value of the field \subsubsection{RPC name:~set\_actions\_after\_reboot} {\bf Overview:} -set accessor message derived from field actions/after\_reboot of object VM +Set the actions/after\_reboot field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_actions_after_reboot (session_id s, VM ref self, on_normal_exit value)\end{verbatim} @@ -2515,7 +2515,7 @@ void \subsubsection{RPC name:~get\_actions\_after\_suspend} {\bf Overview:} -get accessor message derived from field actions/after\_suspend of object VM +Get the actions/after\_suspend field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (on_normal_exit) get_actions_after_suspend (session_id s, VM ref self)\end{verbatim} @@ -2547,7 +2547,7 @@ value of the field \subsubsection{RPC name:~set\_actions\_after\_suspend} {\bf Overview:} -set accessor message derived from field actions/after\_suspend of object VM +Set the actions/after\_suspend field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_actions_after_suspend (session_id s, VM ref self, on_normal_exit value)\end{verbatim} @@ -2581,7 +2581,7 @@ void \subsubsection{RPC name:~get\_actions\_after\_crash} {\bf Overview:} -get accessor message derived from field actions/after\_crash of object VM +Get the actions/after\_crash field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (on_crash_behaviour) get_actions_after_crash (session_id s, VM ref self)\end{verbatim} @@ -2613,7 +2613,7 @@ value of the field \subsubsection{RPC name:~set\_actions\_after\_crash} {\bf Overview:} -set accessor message derived from field actions/after\_crash of object VM +Set the actions/after\_crash field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_actions_after_crash (session_id s, VM ref self, on_crash_behaviour value)\end{verbatim} @@ -2679,7 +2679,7 @@ value of the field \subsubsection{RPC name:~get\_VIFs} {\bf Overview:} -get accessor message derived from field VIFs of object VM +Get the VIFs field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((VIF ref) Set) get_VIFs (session_id s, VM ref self)\end{verbatim} @@ -2711,7 +2711,7 @@ value of the field \subsubsection{RPC name:~get\_VBDs} {\bf Overview:} -get accessor message derived from field VBDs of object VM +Get the VBDs field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((VBD ref) Set) get_VBDs (session_id s, VM ref self)\end{verbatim} @@ -2743,7 +2743,7 @@ value of the field \subsubsection{RPC name:~get\_VTPMs} {\bf Overview:} -get accessor message derived from field VTPMs of object VM +Get the VTPMs field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((VTPM ref) Set) get_VTPMs (session_id s, VM ref self)\end{verbatim} @@ -2775,7 +2775,7 @@ value of the field \subsubsection{RPC name:~get\_bios\_boot} {\bf Overview:} -get accessor message derived from field bios/boot of object VM +Get the bios/boot field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_bios_boot (session_id s, VM ref self)\end{verbatim} @@ -2807,7 +2807,7 @@ value of the field \subsubsection{RPC name:~set\_bios\_boot} {\bf Overview:} -set accessor message derived from field bios/boot of object VM +Set the bios/boot field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_bios_boot (session_id s, VM ref self, string value)\end{verbatim} @@ -2841,7 +2841,7 @@ void \subsubsection{RPC name:~get\_platform\_std\_VGA} {\bf Overview:} -get accessor message derived from field platform/std\_VGA of object VM +Get the platform/std\_VGA field of the given VM. \noindent {\bf Signature:} \begin{verbatim} bool get_platform_std_VGA (session_id s, VM ref self)\end{verbatim} @@ -2873,7 +2873,7 @@ value of the field \subsubsection{RPC name:~set\_platform\_std\_VGA} {\bf Overview:} -set accessor message derived from field platform/std\_VGA of object VM +Set the platform/std\_VGA field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_platform_std_VGA (session_id s, VM ref self, bool value)\end{verbatim} @@ -2907,7 +2907,7 @@ void \subsubsection{RPC name:~get\_platform\_serial} {\bf Overview:} -get accessor message derived from field platform/serial of object VM +Get the platform/serial field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_platform_serial (session_id s, VM ref self)\end{verbatim} @@ -2939,7 +2939,7 @@ value of the field \subsubsection{RPC name:~set\_platform\_serial} {\bf Overview:} -set accessor message derived from field platform/serial of object VM +Set the platform/serial field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_platform_serial (session_id s, VM ref self, string value)\end{verbatim} @@ -2973,7 +2973,7 @@ void \subsubsection{RPC name:~get\_platform\_localtime} {\bf Overview:} -get accessor message derived from field platform/localtime of object VM +Get the platform/localtime field of the given VM. \noindent {\bf Signature:} \begin{verbatim} bool get_platform_localtime (session_id s, VM ref self)\end{verbatim} @@ -3005,7 +3005,7 @@ value of the field \subsubsection{RPC name:~set\_platform\_localtime} {\bf Overview:} -set accessor message derived from field platform/localtime of object VM +Set the platform/localtime field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_platform_localtime (session_id s, VM ref self, bool value)\end{verbatim} @@ -3039,7 +3039,7 @@ void \subsubsection{RPC name:~get\_platform\_clock\_offset} {\bf Overview:} -get accessor message derived from field platform/clock\_offset of object VM +Get the platform/clock\_offset field of the given VM. \noindent {\bf Signature:} \begin{verbatim} bool get_platform_clock_offset (session_id s, VM ref self)\end{verbatim} @@ -3071,7 +3071,7 @@ value of the field \subsubsection{RPC name:~set\_platform\_clock\_offset} {\bf Overview:} -set accessor message derived from field platform/clock\_offset of object VM +Set the platform/clock\_offset field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_platform_clock_offset (session_id s, VM ref self, bool value)\end{verbatim} @@ -3105,7 +3105,7 @@ void \subsubsection{RPC name:~get\_platform\_enable\_audio} {\bf Overview:} -get accessor message derived from field platform/enable\_audio of object VM +Get the platform/enable\_audio field of the given VM. \noindent {\bf Signature:} \begin{verbatim} bool get_platform_enable_audio (session_id s, VM ref self)\end{verbatim} @@ -3137,7 +3137,7 @@ value of the field \subsubsection{RPC name:~set\_platform\_enable\_audio} {\bf Overview:} -set accessor message derived from field platform/enable\_audio of object VM +Set the platform/enable\_audio field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_platform_enable_audio (session_id s, VM ref self, bool value)\end{verbatim} @@ -3171,7 +3171,7 @@ void \subsubsection{RPC name:~get\_builder} {\bf Overview:} -get accessor message derived from field builder of object VM +Get the builder field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_builder (session_id s, VM ref self)\end{verbatim} @@ -3203,7 +3203,7 @@ value of the field \subsubsection{RPC name:~set\_builder} {\bf Overview:} -set accessor message derived from field builder of object VM +Set the builder field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_builder (session_id s, VM ref self, string value)\end{verbatim} @@ -3237,7 +3237,7 @@ void \subsubsection{RPC name:~get\_boot\_method} {\bf Overview:} -get accessor message derived from field boot\_method of object VM +Get the boot\_method field of the given VM. \noindent {\bf Signature:} \begin{verbatim} (boot_type) get_boot_method (session_id s, VM ref self)\end{verbatim} @@ -3269,7 +3269,7 @@ value of the field \subsubsection{RPC name:~set\_boot\_method} {\bf Overview:} -set accessor message derived from field boot\_method of object VM +Set the boot\_method field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_boot_method (session_id s, VM ref self, boot_type value)\end{verbatim} @@ -3303,7 +3303,7 @@ void \subsubsection{RPC name:~get\_kernel\_kernel} {\bf Overview:} -get accessor message derived from field kernel/kernel of object VM +Get the kernel/kernel field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_kernel_kernel (session_id s, VM ref self)\end{verbatim} @@ -3335,7 +3335,7 @@ value of the field \subsubsection{RPC name:~set\_kernel\_kernel} {\bf Overview:} -set accessor message derived from field kernel/kernel of object VM +Set the kernel/kernel field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_kernel_kernel (session_id s, VM ref self, string value)\end{verbatim} @@ -3369,7 +3369,7 @@ void \subsubsection{RPC name:~get\_kernel\_initrd} {\bf Overview:} -get accessor message derived from field kernel/initrd of object VM +Get the kernel/initrd field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_kernel_initrd (session_id s, VM ref self)\end{verbatim} @@ -3401,7 +3401,7 @@ value of the field \subsubsection{RPC name:~set\_kernel\_initrd} {\bf Overview:} -set accessor message derived from field kernel/initrd of object VM +Set the kernel/initrd field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_kernel_initrd (session_id s, VM ref self, string value)\end{verbatim} @@ -3435,7 +3435,7 @@ void \subsubsection{RPC name:~get\_kernel\_args} {\bf Overview:} -get accessor message derived from field kernel/args of object VM +Get the kernel/args field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_kernel_args (session_id s, VM ref self)\end{verbatim} @@ -3467,7 +3467,7 @@ value of the field \subsubsection{RPC name:~set\_kernel\_args} {\bf Overview:} -set accessor message derived from field kernel/args of object VM +Set the kernel/args field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_kernel_args (session_id s, VM ref self, string value)\end{verbatim} @@ -3501,7 +3501,7 @@ void \subsubsection{RPC name:~get\_grub\_cmdline} {\bf Overview:} -get accessor message derived from field grub/cmdline of object VM +Get the grub/cmdline field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_grub_cmdline (session_id s, VM ref self)\end{verbatim} @@ -3533,7 +3533,7 @@ value of the field \subsubsection{RPC name:~set\_grub\_cmdline} {\bf Overview:} -set accessor message derived from field grub/cmdline of object VM +Set the grub/cmdline field of the given VM. \noindent {\bf Signature:} \begin{verbatim} void set_grub_cmdline (session_id s, VM ref self, string value)\end{verbatim} @@ -3567,7 +3567,7 @@ void \subsubsection{RPC name:~get\_PCI\_bus} {\bf Overview:} -get accessor message derived from field PCI\_bus of object VM +Get the PCI\_bus field of the given VM. \noindent {\bf Signature:} \begin{verbatim} string get_PCI_bus (session_id s, VM ref self)\end{verbatim} @@ -3599,7 +3599,7 @@ value of the field \subsubsection{RPC name:~get\_tools\_version} {\bf Overview:} -get accessor message derived from field tools\_version of object VM +Get the tools\_version field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((string -> string) Map) get_tools_version (session_id s, VM ref self)\end{verbatim} @@ -3631,7 +3631,7 @@ value of the field \subsubsection{RPC name:~get\_otherConfig} {\bf Overview:} -get accessor message derived from field otherConfig of object VM +Get the otherConfig field of the given VM. \noindent {\bf Signature:} \begin{verbatim} ((string -> string) Map) get_otherConfig (session_id s, VM ref self)\end{verbatim} @@ -4064,7 +4064,7 @@ A list of all the IDs of all the hosts \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object host +Get the uuid field of the given host. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, host ref self)\end{verbatim} @@ -4096,7 +4096,7 @@ value of the field \subsubsection{RPC name:~get\_name\_label} {\bf Overview:} -get accessor message derived from field name/label of object host +Get the name/label field of the given host. \noindent {\bf Signature:} \begin{verbatim} string get_name_label (session_id s, host ref self)\end{verbatim} @@ -4128,7 +4128,7 @@ value of the field \subsubsection{RPC name:~set\_name\_label} {\bf Overview:} -set accessor message derived from field name/label of object host +Set the name/label field of the given host. \noindent {\bf Signature:} \begin{verbatim} void set_name_label (session_id s, host ref self, string value)\end{verbatim} @@ -4162,7 +4162,7 @@ void \subsubsection{RPC name:~get\_name\_description} {\bf Overview:} -get accessor message derived from field name/description of object host +Get the name/description field of the given host. \noindent {\bf Signature:} \begin{verbatim} string get_name_description (session_id s, host ref self)\end{verbatim} @@ -4194,7 +4194,7 @@ value of the field \subsubsection{RPC name:~set\_name\_description} {\bf Overview:} -set accessor message derived from field name/description of object host +Set the name/description field of the given host. \noindent {\bf Signature:} \begin{verbatim} void set_name_description (session_id s, host ref self, string value)\end{verbatim} @@ -4228,7 +4228,7 @@ void \subsubsection{RPC name:~get\_software\_version} {\bf Overview:} -get accessor message derived from field software\_version of object host +Get the software\_version field of the given host. \noindent {\bf Signature:} \begin{verbatim} ((string -> string) Map) get_software_version (session_id s, host ref self)\end{verbatim} @@ -4260,7 +4260,7 @@ value of the field \subsubsection{RPC name:~get\_resident\_VMs} {\bf Overview:} -get accessor message derived from field resident\_VMs of object host +Get the resident\_VMs field of the given host. \noindent {\bf Signature:} \begin{verbatim} ((VM ref) Set) get_resident_VMs (session_id s, host ref self)\end{verbatim} @@ -4292,7 +4292,7 @@ value of the field \subsubsection{RPC name:~get\_PIFs} {\bf Overview:} -get accessor message derived from field PIFs of object host +Get the PIFs field of the given host. \noindent {\bf Signature:} \begin{verbatim} ((PIF ref) Set) get_PIFs (session_id s, host ref self)\end{verbatim} @@ -4324,7 +4324,7 @@ value of the field \subsubsection{RPC name:~get\_host\_CPUs} {\bf Overview:} -get accessor message derived from field host\_CPUs of object host +Get the host\_CPUs field of the given host. \noindent {\bf Signature:} \begin{verbatim} ((host_cpu ref) Set) get_host_CPUs (session_id s, host ref self)\end{verbatim} @@ -4539,7 +4539,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt utilisation} & float & the current CPU utilis \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object host\_cpu +Get the uuid field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, host_cpu ref self)\end{verbatim} @@ -4571,7 +4571,7 @@ value of the field \subsubsection{RPC name:~get\_host} {\bf Overview:} -get accessor message derived from field host of object host\_cpu +Get the host field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} (host ref) get_host (session_id s, host_cpu ref self)\end{verbatim} @@ -4603,7 +4603,7 @@ value of the field \subsubsection{RPC name:~get\_number} {\bf Overview:} -get accessor message derived from field number of object host\_cpu +Get the number field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} int get_number (session_id s, host_cpu ref self)\end{verbatim} @@ -4635,7 +4635,7 @@ value of the field \subsubsection{RPC name:~get\_vendor} {\bf Overview:} -get accessor message derived from field vendor of object host\_cpu +Get the vendor field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} string get_vendor (session_id s, host_cpu ref self)\end{verbatim} @@ -4667,7 +4667,7 @@ value of the field \subsubsection{RPC name:~get\_speed} {\bf Overview:} -get accessor message derived from field speed of object host\_cpu +Get the speed field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} int get_speed (session_id s, host_cpu ref self)\end{verbatim} @@ -4699,7 +4699,7 @@ value of the field \subsubsection{RPC name:~get\_modelname} {\bf Overview:} -get accessor message derived from field modelname of object host\_cpu +Get the modelname field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} string get_modelname (session_id s, host_cpu ref self)\end{verbatim} @@ -4731,7 +4731,7 @@ value of the field \subsubsection{RPC name:~get\_features} {\bf Overview:} -get accessor message derived from field features of object host\_cpu +Get the features field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} ((cpu_feature) Set) get_features (session_id s, host_cpu ref self)\end{verbatim} @@ -4763,7 +4763,7 @@ value of the field \subsubsection{RPC name:~get\_utilisation} {\bf Overview:} -get accessor message derived from field utilisation of object host\_cpu +Get the utilisation field of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} float get_utilisation (session_id s, host_cpu ref self)\end{verbatim} @@ -4966,7 +4966,7 @@ A list of all the IDs of all the networks \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object network +Get the uuid field of the given network. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, network ref self)\end{verbatim} @@ -4998,7 +4998,7 @@ value of the field \subsubsection{RPC name:~get\_name\_label} {\bf Overview:} -get accessor message derived from field name/label of object network +Get the name/label field of the given network. \noindent {\bf Signature:} \begin{verbatim} string get_name_label (session_id s, network ref self)\end{verbatim} @@ -5030,7 +5030,7 @@ value of the field \subsubsection{RPC name:~set\_name\_label} {\bf Overview:} -set accessor message derived from field name/label of object network +Set the name/label field of the given network. \noindent {\bf Signature:} \begin{verbatim} void set_name_label (session_id s, network ref self, string value)\end{verbatim} @@ -5064,7 +5064,7 @@ void \subsubsection{RPC name:~get\_name\_description} {\bf Overview:} -get accessor message derived from field name/description of object network +Get the name/description field of the given network. \noindent {\bf Signature:} \begin{verbatim} string get_name_description (session_id s, network ref self)\end{verbatim} @@ -5096,7 +5096,7 @@ value of the field \subsubsection{RPC name:~set\_name\_description} {\bf Overview:} -set accessor message derived from field name/description of object network +Set the name/description field of the given network. \noindent {\bf Signature:} \begin{verbatim} void set_name_description (session_id s, network ref self, string value)\end{verbatim} @@ -5130,7 +5130,7 @@ void \subsubsection{RPC name:~get\_VIFs} {\bf Overview:} -get accessor message derived from field VIFs of object network +Get the VIFs field of the given network. \noindent {\bf Signature:} \begin{verbatim} ((VIF ref) Set) get_VIFs (session_id s, network ref self)\end{verbatim} @@ -5162,7 +5162,7 @@ value of the field \subsubsection{RPC name:~get\_PIFs} {\bf Overview:} -get accessor message derived from field PIFs of object network +Get the PIFs field of the given network. \noindent {\bf Signature:} \begin{verbatim} ((PIF ref) Set) get_PIFs (session_id s, network ref self)\end{verbatim} @@ -5194,7 +5194,7 @@ value of the field \subsubsection{RPC name:~get\_default\_gateway} {\bf Overview:} -get accessor message derived from field default\_gateway of object network +Get the default\_gateway field of the given network. \noindent {\bf Signature:} \begin{verbatim} string get_default_gateway (session_id s, network ref self)\end{verbatim} @@ -5226,7 +5226,7 @@ value of the field \subsubsection{RPC name:~set\_default\_gateway} {\bf Overview:} -set accessor message derived from field default\_gateway of object network +Set the default\_gateway field of the given network. \noindent {\bf Signature:} \begin{verbatim} void set_default_gateway (session_id s, network ref self, string value)\end{verbatim} @@ -5260,7 +5260,7 @@ void \subsubsection{RPC name:~get\_default\_netmask} {\bf Overview:} -get accessor message derived from field default\_netmask of object network +Get the default\_netmask field of the given network. \noindent {\bf Signature:} \begin{verbatim} string get_default_netmask (session_id s, network ref self)\end{verbatim} @@ -5292,7 +5292,7 @@ value of the field \subsubsection{RPC name:~set\_default\_netmask} {\bf Overview:} -set accessor message derived from field default\_netmask of object network +Set the default\_netmask field of the given network. \noindent {\bf Signature:} \begin{verbatim} void set_default_netmask (session_id s, network ref self, string value)\end{verbatim} @@ -5511,7 +5511,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object VIF +Get the uuid field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, VIF ref self)\end{verbatim} @@ -5543,7 +5543,7 @@ value of the field \subsubsection{RPC name:~get\_name} {\bf Overview:} -get accessor message derived from field name of object VIF +Get the name field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} string get_name (session_id s, VIF ref self)\end{verbatim} @@ -5575,7 +5575,7 @@ value of the field \subsubsection{RPC name:~set\_name} {\bf Overview:} -set accessor message derived from field name of object VIF +Set the name field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_name (session_id s, VIF ref self, string value)\end{verbatim} @@ -5609,7 +5609,7 @@ void \subsubsection{RPC name:~get\_type} {\bf Overview:} -get accessor message derived from field type of object VIF +Get the type field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} (driver_type) get_type (session_id s, VIF ref self)\end{verbatim} @@ -5641,7 +5641,7 @@ value of the field \subsubsection{RPC name:~set\_type} {\bf Overview:} -set accessor message derived from field type of object VIF +Set the type field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_type (session_id s, VIF ref self, driver_type value)\end{verbatim} @@ -5675,7 +5675,7 @@ void \subsubsection{RPC name:~get\_device} {\bf Overview:} -get accessor message derived from field device of object VIF +Get the device field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} string get_device (session_id s, VIF ref self)\end{verbatim} @@ -5707,7 +5707,7 @@ value of the field \subsubsection{RPC name:~set\_device} {\bf Overview:} -set accessor message derived from field device of object VIF +Set the device field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_device (session_id s, VIF ref self, string value)\end{verbatim} @@ -5741,7 +5741,7 @@ void \subsubsection{RPC name:~get\_network} {\bf Overview:} -get accessor message derived from field network of object VIF +Get the network field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} (network ref) get_network (session_id s, VIF ref self)\end{verbatim} @@ -5773,7 +5773,7 @@ value of the field \subsubsection{RPC name:~set\_network} {\bf Overview:} -set accessor message derived from field network of object VIF +Set the network field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_network (session_id s, VIF ref self, network ref value)\end{verbatim} @@ -5807,7 +5807,7 @@ void \subsubsection{RPC name:~get\_VM} {\bf Overview:} -get accessor message derived from field VM of object VIF +Get the VM field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} (VM ref) get_VM (session_id s, VIF ref self)\end{verbatim} @@ -5839,7 +5839,7 @@ value of the field \subsubsection{RPC name:~set\_VM} {\bf Overview:} -set accessor message derived from field VM of object VIF +Set the VM field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_VM (session_id s, VIF ref self, VM ref value)\end{verbatim} @@ -5873,7 +5873,7 @@ void \subsubsection{RPC name:~get\_MAC} {\bf Overview:} -get accessor message derived from field MAC of object VIF +Get the MAC field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} string get_MAC (session_id s, VIF ref self)\end{verbatim} @@ -5905,7 +5905,7 @@ value of the field \subsubsection{RPC name:~set\_MAC} {\bf Overview:} -set accessor message derived from field MAC of object VIF +Set the MAC field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_MAC (session_id s, VIF ref self, string value)\end{verbatim} @@ -5939,7 +5939,7 @@ void \subsubsection{RPC name:~get\_MTU} {\bf Overview:} -get accessor message derived from field MTU of object VIF +Get the MTU field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} int get_MTU (session_id s, VIF ref self)\end{verbatim} @@ -5971,7 +5971,7 @@ value of the field \subsubsection{RPC name:~set\_MTU} {\bf Overview:} -set accessor message derived from field MTU of object VIF +Set the MTU field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} void set_MTU (session_id s, VIF ref self, int value)\end{verbatim} @@ -6005,7 +6005,7 @@ void \subsubsection{RPC name:~get\_io\_read\_kbs} {\bf Overview:} -get accessor message derived from field io/read\_kbs of object VIF +Get the io/read\_kbs field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} float get_io_read_kbs (session_id s, VIF ref self)\end{verbatim} @@ -6037,7 +6037,7 @@ value of the field \subsubsection{RPC name:~get\_io\_write\_kbs} {\bf Overview:} -get accessor message derived from field io/write\_kbs of object VIF +Get the io/write\_kbs field of the given VIF. \noindent {\bf Signature:} \begin{verbatim} float get_io_write_kbs (session_id s, VIF ref self)\end{verbatim} @@ -6221,7 +6221,7 @@ $\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object PIF +Get the uuid field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, PIF ref self)\end{verbatim} @@ -6253,7 +6253,7 @@ value of the field \subsubsection{RPC name:~get\_name} {\bf Overview:} -get accessor message derived from field name of object PIF +Get the name field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} string get_name (session_id s, PIF ref self)\end{verbatim} @@ -6285,7 +6285,7 @@ value of the field \subsubsection{RPC name:~set\_name} {\bf Overview:} -set accessor message derived from field name of object PIF +Set the name field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} void set_name (session_id s, PIF ref self, string value)\end{verbatim} @@ -6319,7 +6319,7 @@ void \subsubsection{RPC name:~get\_network} {\bf Overview:} -get accessor message derived from field network of object PIF +Get the network field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} (network ref) get_network (session_id s, PIF ref self)\end{verbatim} @@ -6351,7 +6351,7 @@ value of the field \subsubsection{RPC name:~set\_network} {\bf Overview:} -set accessor message derived from field network of object PIF +Set the network field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} void set_network (session_id s, PIF ref self, network ref value)\end{verbatim} @@ -6385,7 +6385,7 @@ void \subsubsection{RPC name:~get\_host} {\bf Overview:} -get accessor message derived from field host of object PIF +Get the host field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} (host ref) get_host (session_id s, PIF ref self)\end{verbatim} @@ -6417,7 +6417,7 @@ value of the field \subsubsection{RPC name:~set\_host} {\bf Overview:} -set accessor message derived from field host of object PIF +Set the host field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} void set_host (session_id s, PIF ref self, host ref value)\end{verbatim} @@ -6451,7 +6451,7 @@ void \subsubsection{RPC name:~get\_MAC} {\bf Overview:} -get accessor message derived from field MAC of object PIF +Get the MAC field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} string get_MAC (session_id s, PIF ref self)\end{verbatim} @@ -6483,7 +6483,7 @@ value of the field \subsubsection{RPC name:~set\_MAC} {\bf Overview:} -set accessor message derived from field MAC of object PIF +Set the MAC field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} void set_MAC (session_id s, PIF ref self, string value)\end{verbatim} @@ -6517,7 +6517,7 @@ void \subsubsection{RPC name:~get\_MTU} {\bf Overview:} -get accessor message derived from field MTU of object PIF +Get the MTU field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} int get_MTU (session_id s, PIF ref self)\end{verbatim} @@ -6549,7 +6549,7 @@ value of the field \subsubsection{RPC name:~set\_MTU} {\bf Overview:} -set accessor message derived from field MTU of object PIF +Set the MTU field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} void set_MTU (session_id s, PIF ref self, int value)\end{verbatim} @@ -6583,7 +6583,7 @@ void \subsubsection{RPC name:~get\_VLAN} {\bf Overview:} -get accessor message derived from field VLAN of object PIF +Get the VLAN field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} string get_VLAN (session_id s, PIF ref self)\end{verbatim} @@ -6615,7 +6615,7 @@ value of the field \subsubsection{RPC name:~set\_VLAN} {\bf Overview:} -set accessor message derived from field VLAN of object PIF +Set the VLAN field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} void set_VLAN (session_id s, PIF ref self, string value)\end{verbatim} @@ -6649,7 +6649,7 @@ void \subsubsection{RPC name:~get\_io\_read\_kbs} {\bf Overview:} -get accessor message derived from field io/read\_kbs of object PIF +Get the io/read\_kbs field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} float get_io_read_kbs (session_id s, PIF ref self)\end{verbatim} @@ -6681,7 +6681,7 @@ value of the field \subsubsection{RPC name:~get\_io\_write\_kbs} {\bf Overview:} -get accessor message derived from field io/write\_kbs of object PIF +Get the io/write\_kbs field of the given PIF. \noindent {\bf Signature:} \begin{verbatim} float get_io_write_kbs (session_id s, PIF ref self)\end{verbatim} @@ -6923,7 +6923,7 @@ A list of all the IDs of all the Storage Repositories \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object SR +Get the uuid field of the given SR. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, SR ref self)\end{verbatim} @@ -6955,7 +6955,7 @@ value of the field \subsubsection{RPC name:~get\_name\_label} {\bf Overview:} -get accessor message derived from field name/label of object SR +Get the name/label field of the given SR. \noindent {\bf Signature:} \begin{verbatim} string get_name_label (session_id s, SR ref self)\end{verbatim} @@ -6987,7 +6987,7 @@ value of the field \subsubsection{RPC name:~set\_name\_label} {\bf Overview:} -set accessor message derived from field name/label of object SR +Set the name/label field of the given SR. \noindent {\bf Signature:} \begin{verbatim} void set_name_label (session_id s, SR ref self, string value)\end{verbatim} @@ -7021,7 +7021,7 @@ void \subsubsection{RPC name:~get\_name\_description} {\bf Overview:} -get accessor message derived from field name/description of object SR +Get the name/description field of the given SR. \noindent {\bf Signature:} \begin{verbatim} string get_name_description (session_id s, SR ref self)\end{verbatim} @@ -7053,7 +7053,7 @@ value of the field \subsubsection{RPC name:~set\_name\_description} {\bf Overview:} -set accessor message derived from field name/description of object SR +Set the name/description field of the given SR. \noindent {\bf Signature:} \begin{verbatim} void set_name_description (session_id s, SR ref self, string value)\end{verbatim} @@ -7087,7 +7087,7 @@ void \subsubsection{RPC name:~get\_VDIs} {\bf Overview:} -get accessor message derived from field VDIs of object SR +Get the VDIs field of the given SR. \noindent {\bf Signature:} \begin{verbatim} ((VDI ref) Set) get_VDIs (session_id s, SR ref self)\end{verbatim} @@ -7119,7 +7119,7 @@ value of the field \subsubsection{RPC name:~get\_virtual\_allocation} {\bf Overview:} -get accessor message derived from field virtual\_allocation of object SR +Get the virtual\_allocation field of the given SR. \noindent {\bf Signature:} \begin{verbatim} int get_virtual_allocation (session_id s, SR ref self)\end{verbatim} @@ -7151,7 +7151,7 @@ value of the field \subsubsection{RPC name:~get\_physical\_utilisation} {\bf Overview:} -get accessor message derived from field physical\_utilisation of object SR +Get the physical\_utilisation field of the given SR. \noindent {\bf Signature:} \begin{verbatim} int get_physical_utilisation (session_id s, SR ref self)\end{verbatim} @@ -7183,7 +7183,7 @@ value of the field \subsubsection{RPC name:~get\_physical\_size} {\bf Overview:} -get accessor message derived from field physical\_size of object SR +Get the physical\_size field of the given SR. \noindent {\bf Signature:} \begin{verbatim} int get_physical_size (session_id s, SR ref self)\end{verbatim} @@ -7215,7 +7215,7 @@ value of the field \subsubsection{RPC name:~get\_type} {\bf Overview:} -get accessor message derived from field type of object SR +Get the type field of the given SR. \noindent {\bf Signature:} \begin{verbatim} string get_type (session_id s, SR ref self)\end{verbatim} @@ -7247,7 +7247,7 @@ value of the field \subsubsection{RPC name:~get\_location} {\bf Overview:} -get accessor message derived from field location of object SR +Get the location field of the given SR. \noindent {\bf Signature:} \begin{verbatim} string get_location (session_id s, SR ref self)\end{verbatim} @@ -7533,7 +7533,7 @@ void \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object VDI +Get the uuid field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, VDI ref self)\end{verbatim} @@ -7565,7 +7565,7 @@ value of the field \subsubsection{RPC name:~get\_name\_label} {\bf Overview:} -get accessor message derived from field name/label of object VDI +Get the name/label field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} string get_name_label (session_id s, VDI ref self)\end{verbatim} @@ -7597,7 +7597,7 @@ value of the field \subsubsection{RPC name:~set\_name\_label} {\bf Overview:} -set accessor message derived from field name/label of object VDI +Set the name/label field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} void set_name_label (session_id s, VDI ref self, string value)\end{verbatim} @@ -7631,7 +7631,7 @@ void \subsubsection{RPC name:~get\_name\_description} {\bf Overview:} -get accessor message derived from field name/description of object VDI +Get the name/description field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} string get_name_description (session_id s, VDI ref self)\end{verbatim} @@ -7663,7 +7663,7 @@ value of the field \subsubsection{RPC name:~set\_name\_description} {\bf Overview:} -set accessor message derived from field name/description of object VDI +Set the name/description field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} void set_name_description (session_id s, VDI ref self, string value)\end{verbatim} @@ -7697,7 +7697,7 @@ void \subsubsection{RPC name:~get\_SR} {\bf Overview:} -get accessor message derived from field SR of object VDI +Get the SR field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} (SR ref) get_SR (session_id s, VDI ref self)\end{verbatim} @@ -7729,7 +7729,7 @@ value of the field \subsubsection{RPC name:~set\_SR} {\bf Overview:} -set accessor message derived from field SR of object VDI +Set the SR field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} void set_SR (session_id s, VDI ref self, SR ref value)\end{verbatim} @@ -7763,7 +7763,7 @@ void \subsubsection{RPC name:~get\_VBDs} {\bf Overview:} -get accessor message derived from field VBDs of object VDI +Get the VBDs field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} ((VBD ref) Set) get_VBDs (session_id s, VDI ref self)\end{verbatim} @@ -7795,7 +7795,7 @@ value of the field \subsubsection{RPC name:~get\_virtual\_size} {\bf Overview:} -get accessor message derived from field virtual\_size of object VDI +Get the virtual\_size field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} int get_virtual_size (session_id s, VDI ref self)\end{verbatim} @@ -7827,7 +7827,7 @@ value of the field \subsubsection{RPC name:~set\_virtual\_size} {\bf Overview:} -set accessor message derived from field virtual\_size of object VDI +Set the virtual\_size field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} void set_virtual_size (session_id s, VDI ref self, int value)\end{verbatim} @@ -7861,7 +7861,7 @@ void \subsubsection{RPC name:~get\_physical\_utilisation} {\bf Overview:} -get accessor message derived from field physical\_utilisation of object VDI +Get the physical\_utilisation field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} int get_physical_utilisation (session_id s, VDI ref self)\end{verbatim} @@ -7893,7 +7893,7 @@ value of the field \subsubsection{RPC name:~get\_sector\_size} {\bf Overview:} -get accessor message derived from field sector\_size of object VDI +Get the sector\_size field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} int get_sector_size (session_id s, VDI ref self)\end{verbatim} @@ -7925,7 +7925,7 @@ value of the field \subsubsection{RPC name:~get\_type} {\bf Overview:} -get accessor message derived from field type of object VDI +Get the type field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} (vdi_type) get_type (session_id s, VDI ref self)\end{verbatim} @@ -7957,7 +7957,7 @@ value of the field \subsubsection{RPC name:~get\_parent} {\bf Overview:} -get accessor message derived from field parent of object VDI +Get the parent field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} (VDI ref) get_parent (session_id s, VDI ref self)\end{verbatim} @@ -7989,7 +7989,7 @@ value of the field \subsubsection{RPC name:~get\_children} {\bf Overview:} -get accessor message derived from field children of object VDI +Get the children field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} ((VDI ref) Set) get_children (session_id s, VDI ref self)\end{verbatim} @@ -8021,7 +8021,7 @@ value of the field \subsubsection{RPC name:~get\_sharable} {\bf Overview:} -get accessor message derived from field sharable of object VDI +Get the sharable field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} bool get_sharable (session_id s, VDI ref self)\end{verbatim} @@ -8053,7 +8053,7 @@ value of the field \subsubsection{RPC name:~set\_sharable} {\bf Overview:} -set accessor message derived from field sharable of object VDI +Set the sharable field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} void set_sharable (session_id s, VDI ref self, bool value)\end{verbatim} @@ -8087,7 +8087,7 @@ void \subsubsection{RPC name:~get\_read\_only} {\bf Overview:} -get accessor message derived from field read\_only of object VDI +Get the read\_only field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} bool get_read_only (session_id s, VDI ref self)\end{verbatim} @@ -8119,7 +8119,7 @@ value of the field \subsubsection{RPC name:~set\_read\_only} {\bf Overview:} -set accessor message derived from field read\_only of object VDI +Set the read\_only field of the given VDI. \noindent {\bf Signature:} \begin{verbatim} void set_read_only (session_id s, VDI ref self, bool value)\end{verbatim} @@ -8370,7 +8370,7 @@ void \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object VBD +Get the uuid field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, VBD ref self)\end{verbatim} @@ -8402,7 +8402,7 @@ value of the field \subsubsection{RPC name:~get\_VM} {\bf Overview:} -get accessor message derived from field VM of object VBD +Get the VM field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} (VM ref) get_VM (session_id s, VBD ref self)\end{verbatim} @@ -8434,7 +8434,7 @@ value of the field \subsubsection{RPC name:~set\_VM} {\bf Overview:} -set accessor message derived from field VM of object VBD +Set the VM field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} void set_VM (session_id s, VBD ref self, VM ref value)\end{verbatim} @@ -8468,7 +8468,7 @@ void \subsubsection{RPC name:~get\_VDI} {\bf Overview:} -get accessor message derived from field VDI of object VBD +Get the VDI field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} (VDI ref) get_VDI (session_id s, VBD ref self)\end{verbatim} @@ -8500,7 +8500,7 @@ value of the field \subsubsection{RPC name:~set\_VDI} {\bf Overview:} -set accessor message derived from field VDI of object VBD +Set the VDI field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} void set_VDI (session_id s, VBD ref self, VDI ref value)\end{verbatim} @@ -8534,7 +8534,7 @@ void \subsubsection{RPC name:~get\_device} {\bf Overview:} -get accessor message derived from field device of object VBD +Get the device field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} string get_device (session_id s, VBD ref self)\end{verbatim} @@ -8566,7 +8566,7 @@ value of the field \subsubsection{RPC name:~set\_device} {\bf Overview:} -set accessor message derived from field device of object VBD +Set the device field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} void set_device (session_id s, VBD ref self, string value)\end{verbatim} @@ -8600,7 +8600,7 @@ void \subsubsection{RPC name:~get\_mode} {\bf Overview:} -get accessor message derived from field mode of object VBD +Get the mode field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} (vbd_mode) get_mode (session_id s, VBD ref self)\end{verbatim} @@ -8632,7 +8632,7 @@ value of the field \subsubsection{RPC name:~set\_mode} {\bf Overview:} -set accessor message derived from field mode of object VBD +Set the mode field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} void set_mode (session_id s, VBD ref self, vbd_mode value)\end{verbatim} @@ -8666,7 +8666,7 @@ void \subsubsection{RPC name:~get\_driver} {\bf Overview:} -get accessor message derived from field driver of object VBD +Get the driver field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} (driver_type) get_driver (session_id s, VBD ref self)\end{verbatim} @@ -8698,7 +8698,7 @@ value of the field \subsubsection{RPC name:~set\_driver} {\bf Overview:} -set accessor message derived from field driver of object VBD +Set the driver field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} void set_driver (session_id s, VBD ref self, driver_type value)\end{verbatim} @@ -8732,7 +8732,7 @@ void \subsubsection{RPC name:~get\_io\_read\_kbs} {\bf Overview:} -get accessor message derived from field io/read\_kbs of object VBD +Get the io/read\_kbs field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} float get_io_read_kbs (session_id s, VBD ref self)\end{verbatim} @@ -8764,7 +8764,7 @@ value of the field \subsubsection{RPC name:~get\_io\_write\_kbs} {\bf Overview:} -get accessor message derived from field io/write\_kbs of object VBD +Get the io/write\_kbs field of the given VBD. \noindent {\bf Signature:} \begin{verbatim} float get_io_write_kbs (session_id s, VBD ref self)\end{verbatim} @@ -8944,7 +8944,7 @@ $\mathit{RO}_\mathit{ins}$ & {\tt instance} & int & the instance number the vir \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object VTPM +Get the uuid field of the given VTPM. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, VTPM ref self)\end{verbatim} @@ -8976,7 +8976,7 @@ value of the field \subsubsection{RPC name:~get\_VM} {\bf Overview:} -get accessor message derived from field VM of object VTPM +Get the VM field of the given VTPM. \noindent {\bf Signature:} \begin{verbatim} (VM ref) get_VM (session_id s, VTPM ref self)\end{verbatim} @@ -9008,7 +9008,7 @@ value of the field \subsubsection{RPC name:~get\_backend} {\bf Overview:} -get accessor message derived from field backend of object VTPM +Get the backend field of the given VTPM. \noindent {\bf Signature:} \begin{verbatim} (VM ref) get_backend (session_id s, VTPM ref self)\end{verbatim} @@ -9040,7 +9040,7 @@ value of the field \subsubsection{RPC name:~get\_driver} {\bf Overview:} -get accessor message derived from field driver of object VTPM +Get the driver field of the given VTPM. \noindent {\bf Signature:} \begin{verbatim} (driver_type) get_driver (session_id s, VTPM ref self)\end{verbatim} @@ -9072,7 +9072,7 @@ value of the field \subsubsection{RPC name:~get\_instance} {\bf Overview:} -get accessor message derived from field instance of object VTPM +Get the instance field of the given VTPM. \noindent {\bf Signature:} \begin{verbatim} int get_instance (session_id s, VTPM ref self)\end{verbatim} @@ -9525,7 +9525,7 @@ $\mathit{RW}$ & {\tt fullname} & string & full name \\ \subsubsection{RPC name:~get\_uuid} {\bf Overview:} -get accessor message derived from field uuid of object user +Get the uuid field of the given user. \noindent {\bf Signature:} \begin{verbatim} string get_uuid (session_id s, user ref self)\end{verbatim} @@ -9557,7 +9557,7 @@ value of the field \subsubsection{RPC name:~get\_short\_name} {\bf Overview:} -get accessor message derived from field short\_name of object user +Get the short\_name field of the given user. \noindent {\bf Signature:} \begin{verbatim} string get_short_name (session_id s, user ref self)\end{verbatim} @@ -9589,7 +9589,7 @@ value of the field \subsubsection{RPC name:~get\_fullname} {\bf Overview:} -get accessor message derived from field fullname of object user +Get the fullname field of the given user. \noindent {\bf Signature:} \begin{verbatim} string get_fullname (session_id s, user ref self)\end{verbatim} @@ -9621,7 +9621,7 @@ value of the field \subsubsection{RPC name:~set\_fullname} {\bf Overview:} -set accessor message derived from field fullname of object user +Set the fullname field of the given user. \noindent {\bf Signature:} \begin{verbatim} void set_fullname (session_id s, user ref self, string value)\end{verbatim} From 46bdf803f9183b9f80375300bab97fbe7f5f3b9a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 13:28:37 +0000 Subject: [PATCH 204/282] More description tidyups -- constructors and destructors this time. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 56 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index de023012ac..e2ce7e51d3 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -400,7 +400,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class session +Create a new session instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (session ref) create (session_id s, session record args)\end{verbatim} @@ -432,7 +432,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class session +Destroy the specified session instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, session ref self)\end{verbatim} @@ -766,7 +766,7 @@ void \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class task +Create a new task instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (task ref) create (session_id s, task record args)\end{verbatim} @@ -798,7 +798,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class task +Destroy the specified task instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, task ref self)\end{verbatim} @@ -3733,7 +3733,7 @@ void \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class VM +Create a new VM instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (VM ref) create (session_id s, VM record args)\end{verbatim} @@ -3765,7 +3765,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class VM +Destroy the specified VM instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, VM ref self)\end{verbatim} @@ -4356,7 +4356,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class host +Create a new host instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (host ref) create (session_id s, host record args)\end{verbatim} @@ -4388,7 +4388,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class host +Destroy the specified host instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, host ref self)\end{verbatim} @@ -4795,7 +4795,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class host\_cpu +Create a new host\_cpu instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (host_cpu ref) create (session_id s, host_cpu record args)\end{verbatim} @@ -4827,7 +4827,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class host\_cpu +Destroy the specified host\_cpu instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, host_cpu ref self)\end{verbatim} @@ -5326,7 +5326,7 @@ void \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class network +Create a new network instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (network ref) create (session_id s, network record args)\end{verbatim} @@ -5358,7 +5358,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class network +Destroy the specified network instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, network ref self)\end{verbatim} @@ -6069,7 +6069,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class VIF +Create a new VIF instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (VIF ref) create (session_id s, VIF record args)\end{verbatim} @@ -6101,7 +6101,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class VIF +Destroy the specified VIF instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, VIF ref self)\end{verbatim} @@ -6713,7 +6713,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class PIF +Create a new PIF instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (PIF ref) create (session_id s, PIF record args)\end{verbatim} @@ -6745,7 +6745,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class PIF +Destroy the specified PIF instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, PIF ref self)\end{verbatim} @@ -7279,7 +7279,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class SR +Create a new SR instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (SR ref) create (session_id s, SR record args)\end{verbatim} @@ -7311,7 +7311,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class SR +Destroy the specified SR instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, SR ref self)\end{verbatim} @@ -8153,7 +8153,7 @@ void \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class VDI +Create a new VDI instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (VDI ref) create (session_id s, VDI record args)\end{verbatim} @@ -8185,7 +8185,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class VDI +Destroy the specified VDI instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, VDI ref self)\end{verbatim} @@ -8796,7 +8796,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class VBD +Create a new VBD instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (VBD ref) create (session_id s, VBD record args)\end{verbatim} @@ -8828,7 +8828,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class VBD +Destroy the specified VBD instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, VBD ref self)\end{verbatim} @@ -9104,7 +9104,7 @@ value of the field \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class VTPM +Create a new VTPM instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (VTPM ref) create (session_id s, VTPM record args)\end{verbatim} @@ -9136,7 +9136,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class VTPM +Destroy the specified VTPM instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, VTPM ref self)\end{verbatim} @@ -9655,7 +9655,7 @@ void \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class user +Create a new user instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (user ref) create (session_id s, user record args)\end{verbatim} @@ -9687,7 +9687,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class user +Destroy the specified user instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, user ref self)\end{verbatim} @@ -9832,7 +9832,7 @@ void \subsubsection{RPC name:~create} {\bf Overview:} -constructor for class debug +Create a new debug instance, and return its handle. \noindent {\bf Signature:} \begin{verbatim} (debug ref) create (session_id s, debug record args)\end{verbatim} @@ -9864,7 +9864,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -destructor for class debug +Destroy the specified debug instance. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, debug ref self)\end{verbatim} From 9b308331446359cdc166b06d613174cc9e289c9a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:01:08 +0000 Subject: [PATCH 205/282] Tidy up the get_record and get_by_uuid descriptions. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 56 +++++++++++++++---------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index e2ce7e51d3..e21ad3ddc6 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -464,7 +464,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the session instance with a particular uuid +Get a reference to the session instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (session ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -496,7 +496,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class session +Get a record containing the current state of the given session. \noindent {\bf Signature:} \begin{verbatim} (session record) get_record (session_id s, session ref self)\end{verbatim} @@ -830,7 +830,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the task instance with a particular uuid +Get a reference to the task instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (task ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -862,7 +862,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class task +Get a record containing the current state of the given task. \noindent {\bf Signature:} \begin{verbatim} (task record) get_record (session_id s, task ref self)\end{verbatim} @@ -3797,7 +3797,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the VM instance with a particular uuid +Get a reference to the VM instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (VM ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -3829,7 +3829,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class VM +Get a record containing the current state of the given VM. \noindent {\bf Signature:} \begin{verbatim} (VM record) get_record (session_id s, VM ref self)\end{verbatim} @@ -4420,7 +4420,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the host instance with a particular uuid +Get a reference to the host instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (host ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -4452,7 +4452,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class host +Get a record containing the current state of the given host. \noindent {\bf Signature:} \begin{verbatim} (host record) get_record (session_id s, host ref self)\end{verbatim} @@ -4859,7 +4859,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the host\_cpu instance with a particular uuid +Get a reference to the host\_cpu instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (host_cpu ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -4891,7 +4891,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class host\_cpu +Get a record containing the current state of the given host\_cpu. \noindent {\bf Signature:} \begin{verbatim} (host_cpu record) get_record (session_id s, host_cpu ref self)\end{verbatim} @@ -5390,7 +5390,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the network instance with a particular uuid +Get a reference to the network instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (network ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -5422,7 +5422,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class network +Get a record containing the current state of the given network. \noindent {\bf Signature:} \begin{verbatim} (network record) get_record (session_id s, network ref self)\end{verbatim} @@ -6133,7 +6133,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the VIF instance with a particular uuid +Get a reference to the VIF instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (VIF ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -6165,7 +6165,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class VIF +Get a record containing the current state of the given VIF. \noindent {\bf Signature:} \begin{verbatim} (VIF record) get_record (session_id s, VIF ref self)\end{verbatim} @@ -6777,7 +6777,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the PIF instance with a particular uuid +Get a reference to the PIF instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (PIF ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -6809,7 +6809,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class PIF +Get a record containing the current state of the given PIF. \noindent {\bf Signature:} \begin{verbatim} (PIF record) get_record (session_id s, PIF ref self)\end{verbatim} @@ -7343,7 +7343,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the SR instance with a particular uuid +Get a reference to the SR instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (SR ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -7375,7 +7375,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class SR +Get a record containing the current state of the given SR. \noindent {\bf Signature:} \begin{verbatim} (SR record) get_record (session_id s, SR ref self)\end{verbatim} @@ -8217,7 +8217,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the VDI instance with a particular uuid +Get a reference to the VDI instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (VDI ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -8249,7 +8249,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class VDI +Get a record containing the current state of the given VDI. \noindent {\bf Signature:} \begin{verbatim} (VDI record) get_record (session_id s, VDI ref self)\end{verbatim} @@ -8860,7 +8860,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the VBD instance with a particular uuid +Get a reference to the VBD instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (VBD ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -8892,7 +8892,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class VBD +Get a record containing the current state of the given VBD. \noindent {\bf Signature:} \begin{verbatim} (VBD record) get_record (session_id s, VBD ref self)\end{verbatim} @@ -9168,7 +9168,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the VTPM instance with a particular uuid +Get a reference to the VTPM instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (VTPM ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -9200,7 +9200,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class VTPM +Get a record containing the current state of the given VTPM. \noindent {\bf Signature:} \begin{verbatim} (VTPM record) get_record (session_id s, VTPM ref self)\end{verbatim} @@ -9719,7 +9719,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the user instance with a particular uuid +Get a reference to the user instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (user ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -9751,7 +9751,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class user +Get a record containing the current state of the given user. \noindent {\bf Signature:} \begin{verbatim} (user record) get_record (session_id s, user ref self)\end{verbatim} @@ -9896,7 +9896,7 @@ void \subsubsection{RPC name:~get\_by\_uuid} {\bf Overview:} -returns the debug instance with a particular uuid +Get a reference to the debug instance with the specified UUID. \noindent {\bf Signature:} \begin{verbatim} (debug ref) get_by_uuid (session_id s, string uuid)\end{verbatim} @@ -9928,7 +9928,7 @@ reference to the object \subsubsection{RPC name:~get\_record} {\bf Overview:} -returns a record containing the state of an instance of class debug +Get a record containing the current state of the given debug. \noindent {\bf Signature:} \begin{verbatim} (debug record) get_record (session_id s, debug ref self)\end{verbatim} From 449775b249c3a63547f27afff10fc9f24e60ad26 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:05:23 +0000 Subject: [PATCH 206/282] Clarify that the self parameter is an object reference, not the instance (i.e. record) itself. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 422 +++++++++++++++--------------- 1 file changed, 211 insertions(+), 211 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index e21ad3ddc6..a51f35743c 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -349,7 +349,7 @@ Get the this\_host field of the given session. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt session ref } & self & object instance \\ \hline +{\tt session ref } & self & reference to the object \\ \hline \end{tabular} @@ -381,7 +381,7 @@ Get the this\_user field of the given session. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt session ref } & self & object instance \\ \hline +{\tt session ref } & self & reference to the object \\ \hline \end{tabular} @@ -445,7 +445,7 @@ Destroy the specified session instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt session ref } & self & object instance \\ \hline +{\tt session ref } & self & reference to the object \\ \hline \end{tabular} @@ -615,7 +615,7 @@ Get the uuid field of the given task. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & self & object instance \\ \hline +{\tt task ref } & self & reference to the object \\ \hline \end{tabular} @@ -647,7 +647,7 @@ Get the name/label field of the given task. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & self & object instance \\ \hline +{\tt task ref } & self & reference to the object \\ \hline \end{tabular} @@ -679,7 +679,7 @@ Set the name/label field of the given task. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & self & object instance \\ \hline +{\tt task ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -713,7 +713,7 @@ Get the name/description field of the given task. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & self & object instance \\ \hline +{\tt task ref } & self & reference to the object \\ \hline \end{tabular} @@ -745,7 +745,7 @@ Set the name/description field of the given task. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & self & object instance \\ \hline +{\tt task ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -811,7 +811,7 @@ Destroy the specified task instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & self & object instance \\ \hline +{\tt task ref } & self & reference to the object \\ \hline \end{tabular} @@ -1348,7 +1348,7 @@ Get the uuid field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1380,7 +1380,7 @@ Get the power\_state field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1412,7 +1412,7 @@ Get the name/label field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1444,7 +1444,7 @@ Set the name/label field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -1478,7 +1478,7 @@ Get the name/description field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1510,7 +1510,7 @@ Set the name/description field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -1544,7 +1544,7 @@ Get the user\_version field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1576,7 +1576,7 @@ Set the user\_version field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt int } & value & New value to set \\ \hline @@ -1610,7 +1610,7 @@ Get the is\_a\_template field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1642,7 +1642,7 @@ Set the is\_a\_template field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -1676,7 +1676,7 @@ Get the resident\_on field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1708,7 +1708,7 @@ Get the memory/static\_max field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1740,7 +1740,7 @@ Get the memory/dynamic\_max field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1772,7 +1772,7 @@ Set the memory/dynamic\_max field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt int } & value & New value to set \\ \hline @@ -1806,7 +1806,7 @@ Get the memory/actual field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1838,7 +1838,7 @@ Get the memory/dynamic\_min field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1870,7 +1870,7 @@ Set the memory/dynamic\_min field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt int } & value & New value to set \\ \hline @@ -1904,7 +1904,7 @@ Get the memory/static\_min field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1936,7 +1936,7 @@ Get the VCPUs/policy field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -1968,7 +1968,7 @@ Set the VCPUs/policy field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -2002,7 +2002,7 @@ Get the VCPUs/params field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2034,7 +2034,7 @@ Set the VCPUs/params field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -2068,7 +2068,7 @@ Get the VCPUs/number field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2100,7 +2100,7 @@ Get the VCPUs/utilisation field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2132,7 +2132,7 @@ Get the VCPUs/features/required field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2164,7 +2164,7 @@ Get the VCPUs/features/can\_use field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2196,7 +2196,7 @@ Get the VCPUs/features/force\_on field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2228,7 +2228,7 @@ set add message derived from field VCPUs/features/force\_on of object VM \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt cpu\_feature } & value & New value to add \\ \hline @@ -2262,7 +2262,7 @@ set remove message derived from field VCPUs/features/force\_on of object VM \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt cpu\_feature } & value & Value to remove \\ \hline @@ -2296,7 +2296,7 @@ Get the VCPUs/features/force\_off field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2328,7 +2328,7 @@ set add message derived from field VCPUs/features/force\_off of object VM \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt cpu\_feature } & value & New value to add \\ \hline @@ -2362,7 +2362,7 @@ set remove message derived from field VCPUs/features/force\_off of object VM \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt cpu\_feature } & value & Value to remove \\ \hline @@ -2396,7 +2396,7 @@ Get the actions/after\_shutdown field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2428,7 +2428,7 @@ Set the actions/after\_shutdown field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt on\_normal\_exit } & value & New value to set \\ \hline @@ -2462,7 +2462,7 @@ Get the actions/after\_reboot field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2494,7 +2494,7 @@ Set the actions/after\_reboot field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt on\_normal\_exit } & value & New value to set \\ \hline @@ -2528,7 +2528,7 @@ Get the actions/after\_suspend field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2560,7 +2560,7 @@ Set the actions/after\_suspend field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt on\_normal\_exit } & value & New value to set \\ \hline @@ -2594,7 +2594,7 @@ Get the actions/after\_crash field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2626,7 +2626,7 @@ Set the actions/after\_crash field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt on\_crash\_behaviour } & value & New value to set \\ \hline @@ -2660,7 +2660,7 @@ Get the consoles field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2692,7 +2692,7 @@ Get the VIFs field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2724,7 +2724,7 @@ Get the VBDs field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2756,7 +2756,7 @@ Get the VTPMs field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2788,7 +2788,7 @@ Get the bios/boot field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2820,7 +2820,7 @@ Set the bios/boot field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -2854,7 +2854,7 @@ Get the platform/std\_VGA field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2886,7 +2886,7 @@ Set the platform/std\_VGA field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -2920,7 +2920,7 @@ Get the platform/serial field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -2952,7 +2952,7 @@ Set the platform/serial field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -2986,7 +2986,7 @@ Get the platform/localtime field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3018,7 +3018,7 @@ Set the platform/localtime field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -3052,7 +3052,7 @@ Get the platform/clock\_offset field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3084,7 +3084,7 @@ Set the platform/clock\_offset field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -3118,7 +3118,7 @@ Get the platform/enable\_audio field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3150,7 +3150,7 @@ Set the platform/enable\_audio field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -3184,7 +3184,7 @@ Get the builder field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3216,7 +3216,7 @@ Set the builder field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -3250,7 +3250,7 @@ Get the boot\_method field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3282,7 +3282,7 @@ Set the boot\_method field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt boot\_type } & value & New value to set \\ \hline @@ -3316,7 +3316,7 @@ Get the kernel/kernel field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3348,7 +3348,7 @@ Set the kernel/kernel field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -3382,7 +3382,7 @@ Get the kernel/initrd field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3414,7 +3414,7 @@ Set the kernel/initrd field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -3448,7 +3448,7 @@ Get the kernel/args field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3480,7 +3480,7 @@ Set the kernel/args field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -3514,7 +3514,7 @@ Get the grub/cmdline field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3546,7 +3546,7 @@ Set the grub/cmdline field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -3580,7 +3580,7 @@ Get the PCI\_bus field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3612,7 +3612,7 @@ Get the tools\_version field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3644,7 +3644,7 @@ Get the otherConfig field of the given VM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -3676,7 +3676,7 @@ map add message derived from field otherConfig of object VM \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & key & Key to add \\ \hline @@ -3712,7 +3712,7 @@ map remove message derived from field otherConfig of object VM \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline {\tt string } & key & Key to remove \\ \hline @@ -3778,7 +3778,7 @@ Destroy the specified VM instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VM ref } & self & object instance \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline \end{tabular} @@ -4077,7 +4077,7 @@ Get the uuid field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4109,7 +4109,7 @@ Get the name/label field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4141,7 +4141,7 @@ Set the name/label field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -4175,7 +4175,7 @@ Get the name/description field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4207,7 +4207,7 @@ Set the name/description field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -4241,7 +4241,7 @@ Get the software\_version field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4273,7 +4273,7 @@ Get the resident\_VMs field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4305,7 +4305,7 @@ Get the PIFs field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4337,7 +4337,7 @@ Get the host\_CPUs field of the given host. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4401,7 +4401,7 @@ Destroy the specified host instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host ref } & self & object instance \\ \hline +{\tt host ref } & self & reference to the object \\ \hline \end{tabular} @@ -4552,7 +4552,7 @@ Get the uuid field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4584,7 +4584,7 @@ Get the host field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4616,7 +4616,7 @@ Get the number field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4648,7 +4648,7 @@ Get the vendor field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4680,7 +4680,7 @@ Get the speed field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4712,7 +4712,7 @@ Get the modelname field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4744,7 +4744,7 @@ Get the features field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4776,7 +4776,7 @@ Get the utilisation field of the given host\_cpu. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4840,7 +4840,7 @@ Destroy the specified host\_cpu instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt host\_cpu ref } & self & object instance \\ \hline +{\tt host\_cpu ref } & self & reference to the object \\ \hline \end{tabular} @@ -4979,7 +4979,7 @@ Get the uuid field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5011,7 +5011,7 @@ Get the name/label field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5043,7 +5043,7 @@ Set the name/label field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5077,7 +5077,7 @@ Get the name/description field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5109,7 +5109,7 @@ Set the name/description field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5143,7 +5143,7 @@ Get the VIFs field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5175,7 +5175,7 @@ Get the PIFs field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5207,7 +5207,7 @@ Get the default\_gateway field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5239,7 +5239,7 @@ Set the default\_gateway field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5273,7 +5273,7 @@ Get the default\_netmask field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5305,7 +5305,7 @@ Set the default\_netmask field of the given network. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5371,7 +5371,7 @@ Destroy the specified network instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt network ref } & self & object instance \\ \hline +{\tt network ref } & self & reference to the object \\ \hline \end{tabular} @@ -5524,7 +5524,7 @@ Get the uuid field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5556,7 +5556,7 @@ Get the name field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5588,7 +5588,7 @@ Set the name field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5622,7 +5622,7 @@ Get the type field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5654,7 +5654,7 @@ Set the type field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt driver\_type } & value & New value to set \\ \hline @@ -5688,7 +5688,7 @@ Get the device field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5720,7 +5720,7 @@ Set the device field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5754,7 +5754,7 @@ Get the network field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5786,7 +5786,7 @@ Set the network field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt network ref } & value & New value to set \\ \hline @@ -5820,7 +5820,7 @@ Get the VM field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5852,7 +5852,7 @@ Set the VM field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt VM ref } & value & New value to set \\ \hline @@ -5886,7 +5886,7 @@ Get the MAC field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5918,7 +5918,7 @@ Set the MAC field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -5952,7 +5952,7 @@ Get the MTU field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -5984,7 +5984,7 @@ Set the MTU field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline {\tt int } & value & New value to set \\ \hline @@ -6018,7 +6018,7 @@ Get the io/read\_kbs field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6050,7 +6050,7 @@ Get the io/write\_kbs field of the given VIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6114,7 +6114,7 @@ Destroy the specified VIF instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VIF ref } & self & object instance \\ \hline +{\tt VIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6234,7 +6234,7 @@ Get the uuid field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6266,7 +6266,7 @@ Get the name field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6298,7 +6298,7 @@ Set the name field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -6332,7 +6332,7 @@ Get the network field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6364,7 +6364,7 @@ Set the network field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline {\tt network ref } & value & New value to set \\ \hline @@ -6398,7 +6398,7 @@ Get the host field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6430,7 +6430,7 @@ Set the host field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline {\tt host ref } & value & New value to set \\ \hline @@ -6464,7 +6464,7 @@ Get the MAC field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6496,7 +6496,7 @@ Set the MAC field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -6530,7 +6530,7 @@ Get the MTU field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6562,7 +6562,7 @@ Set the MTU field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline {\tt int } & value & New value to set \\ \hline @@ -6596,7 +6596,7 @@ Get the VLAN field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6628,7 +6628,7 @@ Set the VLAN field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -6662,7 +6662,7 @@ Get the io/read\_kbs field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6694,7 +6694,7 @@ Get the io/write\_kbs field of the given PIF. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6758,7 +6758,7 @@ Destroy the specified PIF instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt PIF ref } & self & object instance \\ \hline +{\tt PIF ref } & self & reference to the object \\ \hline \end{tabular} @@ -6936,7 +6936,7 @@ Get the uuid field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -6968,7 +6968,7 @@ Get the name/label field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7000,7 +7000,7 @@ Set the name/label field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -7034,7 +7034,7 @@ Get the name/description field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7066,7 +7066,7 @@ Set the name/description field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -7100,7 +7100,7 @@ Get the VDIs field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7132,7 +7132,7 @@ Get the virtual\_allocation field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7164,7 +7164,7 @@ Get the physical\_utilisation field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7196,7 +7196,7 @@ Get the physical\_size field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7228,7 +7228,7 @@ Get the type field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7260,7 +7260,7 @@ Get the location field of the given SR. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7324,7 +7324,7 @@ Destroy the specified SR instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt SR ref } & self & object instance \\ \hline +{\tt SR ref } & self & reference to the object \\ \hline \end{tabular} @@ -7546,7 +7546,7 @@ Get the uuid field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7578,7 +7578,7 @@ Get the name/label field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7610,7 +7610,7 @@ Set the name/label field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -7644,7 +7644,7 @@ Get the name/description field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7676,7 +7676,7 @@ Set the name/description field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -7710,7 +7710,7 @@ Get the SR field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7742,7 +7742,7 @@ Set the SR field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline {\tt SR ref } & value & New value to set \\ \hline @@ -7776,7 +7776,7 @@ Get the VBDs field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7808,7 +7808,7 @@ Get the virtual\_size field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7840,7 +7840,7 @@ Set the virtual\_size field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline {\tt int } & value & New value to set \\ \hline @@ -7874,7 +7874,7 @@ Get the physical\_utilisation field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7906,7 +7906,7 @@ Get the sector\_size field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7938,7 +7938,7 @@ Get the type field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -7970,7 +7970,7 @@ Get the parent field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -8002,7 +8002,7 @@ Get the children field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -8034,7 +8034,7 @@ Get the sharable field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -8066,7 +8066,7 @@ Set the sharable field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -8100,7 +8100,7 @@ Get the read\_only field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -8132,7 +8132,7 @@ Set the read\_only field of the given VDI. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline {\tt bool } & value & New value to set \\ \hline @@ -8198,7 +8198,7 @@ Destroy the specified VDI instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VDI ref } & self & object instance \\ \hline +{\tt VDI ref } & self & reference to the object \\ \hline \end{tabular} @@ -8383,7 +8383,7 @@ Get the uuid field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8415,7 +8415,7 @@ Get the VM field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8447,7 +8447,7 @@ Set the VM field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline {\tt VM ref } & value & New value to set \\ \hline @@ -8481,7 +8481,7 @@ Get the VDI field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8513,7 +8513,7 @@ Set the VDI field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline {\tt VDI ref } & value & New value to set \\ \hline @@ -8547,7 +8547,7 @@ Get the device field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8579,7 +8579,7 @@ Set the device field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -8613,7 +8613,7 @@ Get the mode field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8645,7 +8645,7 @@ Set the mode field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline {\tt vbd\_mode } & value & New value to set \\ \hline @@ -8679,7 +8679,7 @@ Get the driver field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8711,7 +8711,7 @@ Set the driver field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline {\tt driver\_type } & value & New value to set \\ \hline @@ -8745,7 +8745,7 @@ Get the io/read\_kbs field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8777,7 +8777,7 @@ Get the io/write\_kbs field of the given VBD. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8841,7 +8841,7 @@ Destroy the specified VBD instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VBD ref } & self & object instance \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline \end{tabular} @@ -8957,7 +8957,7 @@ Get the uuid field of the given VTPM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VTPM ref } & self & object instance \\ \hline +{\tt VTPM ref } & self & reference to the object \\ \hline \end{tabular} @@ -8989,7 +8989,7 @@ Get the VM field of the given VTPM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VTPM ref } & self & object instance \\ \hline +{\tt VTPM ref } & self & reference to the object \\ \hline \end{tabular} @@ -9021,7 +9021,7 @@ Get the backend field of the given VTPM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VTPM ref } & self & object instance \\ \hline +{\tt VTPM ref } & self & reference to the object \\ \hline \end{tabular} @@ -9053,7 +9053,7 @@ Get the driver field of the given VTPM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VTPM ref } & self & object instance \\ \hline +{\tt VTPM ref } & self & reference to the object \\ \hline \end{tabular} @@ -9085,7 +9085,7 @@ Get the instance field of the given VTPM. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VTPM ref } & self & object instance \\ \hline +{\tt VTPM ref } & self & reference to the object \\ \hline \end{tabular} @@ -9149,7 +9149,7 @@ Destroy the specified VTPM instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt VTPM ref } & self & object instance \\ \hline +{\tt VTPM ref } & self & reference to the object \\ \hline \end{tabular} @@ -9360,7 +9360,7 @@ Destroy the specified console instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt console ref } & self & object instance \\ \hline +{\tt console ref } & self & reference to the object \\ \hline \end{tabular} @@ -9392,7 +9392,7 @@ Get the uuid field of the given console. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt console ref } & self & object instance \\ \hline +{\tt console ref } & self & reference to the object \\ \hline \end{tabular} @@ -9424,7 +9424,7 @@ Get the protocol field of the given console. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt console ref } & self & object instance \\ \hline +{\tt console ref } & self & reference to the object \\ \hline \end{tabular} @@ -9456,7 +9456,7 @@ Get the uri field of the given console. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt console ref } & self & object instance \\ \hline +{\tt console ref } & self & reference to the object \\ \hline \end{tabular} @@ -9488,7 +9488,7 @@ Get the VM field of the given console. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt console ref } & self & object instance \\ \hline +{\tt console ref } & self & reference to the object \\ \hline \end{tabular} @@ -9538,7 +9538,7 @@ Get the uuid field of the given user. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt user ref } & self & object instance \\ \hline +{\tt user ref } & self & reference to the object \\ \hline \end{tabular} @@ -9570,7 +9570,7 @@ Get the short\_name field of the given user. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt user ref } & self & object instance \\ \hline +{\tt user ref } & self & reference to the object \\ \hline \end{tabular} @@ -9602,7 +9602,7 @@ Get the fullname field of the given user. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt user ref } & self & object instance \\ \hline +{\tt user ref } & self & reference to the object \\ \hline \end{tabular} @@ -9634,7 +9634,7 @@ Set the fullname field of the given user. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt user ref } & self & object instance \\ \hline +{\tt user ref } & self & reference to the object \\ \hline {\tt string } & value & New value to set \\ \hline @@ -9700,7 +9700,7 @@ Destroy the specified user instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt user ref } & self & object instance \\ \hline +{\tt user ref } & self & reference to the object \\ \hline \end{tabular} @@ -9877,7 +9877,7 @@ Destroy the specified debug instance. \begin{tabular}{|c|c|p{7cm}|} \hline {\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt debug ref } & self & object instance \\ \hline +{\tt debug ref } & self & reference to the object \\ \hline \end{tabular} From 16eaa7dd1c9db6713f6fb86407540ff6db064fb4 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:13:33 +0000 Subject: [PATCH 207/282] Tidy up the get_by_name_label description. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index a51f35743c..71ffb8b524 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -894,7 +894,7 @@ all fields from the object \subsubsection{RPC name:~get\_by\_name\_label} {\bf Overview:} -returns the task instance with a particular name label +Get all the task instances with the given label. \noindent {\bf Signature:} \begin{verbatim} ((task ref) Set) get_by_name_label (session_id s, string label)\end{verbatim} @@ -3861,7 +3861,7 @@ all fields from the object \subsubsection{RPC name:~get\_by\_name\_label} {\bf Overview:} -returns the VM instance with a particular name label +Get all the VM instances with the given label. \noindent {\bf Signature:} \begin{verbatim} ((VM ref) Set) get_by_name_label (session_id s, string label)\end{verbatim} @@ -4484,7 +4484,7 @@ all fields from the object \subsubsection{RPC name:~get\_by\_name\_label} {\bf Overview:} -returns the host instance with a particular name label +Get all the host instances with the given label. \noindent {\bf Signature:} \begin{verbatim} ((host ref) Set) get_by_name_label (session_id s, string label)\end{verbatim} @@ -5454,7 +5454,7 @@ all fields from the object \subsubsection{RPC name:~get\_by\_name\_label} {\bf Overview:} -returns the network instance with a particular name label +Get all the network instances with the given label. \noindent {\bf Signature:} \begin{verbatim} ((network ref) Set) get_by_name_label (session_id s, string label)\end{verbatim} @@ -7407,7 +7407,7 @@ all fields from the object \subsubsection{RPC name:~get\_by\_name\_label} {\bf Overview:} -returns the SR instance with a particular name label +Get all the SR instances with the given label. \noindent {\bf Signature:} \begin{verbatim} ((SR ref) Set) get_by_name_label (session_id s, string label)\end{verbatim} @@ -8281,7 +8281,7 @@ all fields from the object \subsubsection{RPC name:~get\_by\_name\_label} {\bf Overview:} -returns the VDI instance with a particular name label +Get all the VDI instances with the given label. \noindent {\bf Signature:} \begin{verbatim} ((VDI ref) Set) get_by_name_label (session_id s, string label)\end{verbatim} From b7bca7b892104e5efb352c165412a7ddd19ebdcf Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:20:03 +0000 Subject: [PATCH 208/282] Improved task handling model. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 319 ++++++++++++++++++++++++++---- 1 file changed, 280 insertions(+), 39 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 71ffb8b524..cfd264bf94 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -109,6 +109,7 @@ The following enumeration types are used: \hline \end{longtable} +\vspace{1cm} \begin{longtable}{|ll|} \hline {\tt enum vdi\_type} & \\ @@ -133,6 +134,17 @@ The following enumeration types are used: \hline \end{longtable} +\vspace{1cm} +\begin{longtable}{|ll|} +\hline +{\tt enum task\_status\_type} & \\ +\hline +\hspace{0.5cm}{\tt pending} & task is in progress \\ +\hspace{0.5cm}{\tt success} & task was completed successfully \\ +\hspace{0.5cm}{\tt failure} & task has failed \\ +\hline +\end{longtable} + \vspace{1cm} \begin{longtable}{|ll|} \hline @@ -273,6 +285,7 @@ The following enumeration types are used: \hline Quals & Field & Type & Description \\ \hline +$\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\ $\mathit{RO}_\mathit{ins}$ & {\tt this\_host} & host ref & Currently connected host \\ $\mathit{RO}_\mathit{ins}$ & {\tt this\_user} & user ref & Currently connected user \\ \hline @@ -330,6 +343,38 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_uuid} + +{\bf Overview:} +Get the uuid field of the given session. + + \noindent {\bf Signature:} +\begin{verbatim} string get_uuid (session_id s, session ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt session ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +string +} + + +value of the field \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -540,48 +585,23 @@ Quals & Field & Type & Description \\ $\mathit{RO}_\mathit{run}$ & {\tt uuid} & string & unique identifier/object reference \\ $\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\ $\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\ +$\mathit{RO}_\mathit{run}$ & {\tt status} & task\_status\_type & current status of the task \\ +$\mathit{RO}_\mathit{run}$ & {\tt progress} & int & if the task is still pending, this field contains the estimated percentage complete (0-100). If task has completed (successfully or unsuccessfully) this should be 100. \\ +$\mathit{RO}_\mathit{run}$ & {\tt eta} & datetime & if the task is still pending, this field contains the estimated completion time. If the task has finished (successfully or not) it contains the time the task finished. \\ +$\mathit{RO}_\mathit{run}$ & {\tt type} & string & if the task has completed successfully, this field contains the type of the encoded result (i.e. name of the class whose reference is in the result field). Undefined otherwise. \\ +$\mathit{RO}_\mathit{run}$ & {\tt result} & string & if the task has completed successfully, this field contains the result value (either Void or an object reference). Undefined otherwise. \\ +$\mathit{RO}_\mathit{run}$ & {\tt error\_code} & int & if the task has failed, this field contains the error code. Undefined otherwise. \\ +$\mathit{RO}_\mathit{run}$ & {\tt error\_info} & string Set & if the task has failed, this field contains the set of associated error strings. Undefined otherwise. \\ \hline \end{longtable} \subsection{Additional RPCs associated with class: task} -\subsubsection{RPC name:~get\_status} +\subsubsection{RPC name:~get\_all} {\bf Overview:} -Poll a running asynchronous RPC invocation and query its status +Return a list of all the tasks known to the system \noindent {\bf Signature:} -\begin{verbatim} (uuid ref) get_status (session_id s, task ref task)\end{verbatim} - - -\noindent{\bf Arguments:} - - -\vspace{0.3cm} -\begin{tabular}{|c|c|p{7cm}|} - \hline -{\bf type} & {\bf name} & {\bf description} \\ \hline -{\tt task ref } & task & The ID of the RPC call to poll \\ \hline - -\end{tabular} - -\vspace{0.3cm} - - \noindent {\bf Return Type:} -{\tt -uuid ref -} - - -String describing status of specified asynchronous RPC invocation, including estimated completion time -\vspace{0.3cm} -\vspace{0.3cm} -\vspace{0.3cm} -\subsubsection{RPC name:~get\_all\_tasks} - -{\bf Overview:} -List all asynchronous RPC calls currently executing - - \noindent {\bf Signature:} -\begin{verbatim} ((task ref) Set) get_all_tasks (session_id s)\end{verbatim} +\begin{verbatim} ((task ref) Set) get_all (session_id s)\end{verbatim} \vspace{0.3cm} @@ -592,10 +612,7 @@ List all asynchronous RPC calls currently executing } -A list of tasks currently executing. Note that -tasks are associated with users rather than sessions. Thus, if you logout and -login again with a different session but the same user, this function will still -return the user's running tasks. +references to all objects \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -760,6 +777,230 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_status} + +{\bf Overview:} +Get the status field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} (task_status_type) get_status (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +task\_status\_type +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_progress} + +{\bf Overview:} +Get the progress field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} int get_progress (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +int +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_eta} + +{\bf Overview:} +Get the eta field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} datetime get_eta (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +datetime +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_type} + +{\bf Overview:} +Get the type field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} string get_type (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +string +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_result} + +{\bf Overview:} +Get the result field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} string get_result (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +string +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_error\_code} + +{\bf Overview:} +Get the error\_code field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} int get_error_code (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +int +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_error\_info} + +{\bf Overview:} +Get the error\_info field of the given task. + + \noindent {\bf Signature:} +\begin{verbatim} (string Set) get_error_info (session_id s, task ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt task ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +string Set +} + + +value of the field \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} From 41eb2f8c0de0fd155b40d10512bab82956cf5b7a Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:38:29 +0000 Subject: [PATCH 209/282] Clarify that memory values are in bytes. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index cfd264bf94..18e9ba8ec8 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -1183,11 +1183,11 @@ $\mathit{RW}$ & {\tt name/description} & string & a notes field containg human- $\mathit{RW}$ & {\tt user\_version} & int & a user version number for this machine \\ $\mathit{RW}$ & {\tt is\_a\_template} & bool & true if this is a template. Template VMs can never be started, they are used only for cloning other VMs \\ $\mathit{RO}_\mathit{run}$ & {\tt resident\_on} & host ref & the host the VM is currently resident on \\ -$\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_max} & int & Statically-set (i.e. absolute) maximum \\ -$\mathit{RW}$ & {\tt memory/dynamic\_max} & int & Dynamic maximum \\ -$\mathit{RO}_\mathit{run}$ & {\tt memory/actual} & int & Guest's actual usage \\ -$\mathit{RW}$ & {\tt memory/dynamic\_min} & int & Dynamic minimum \\ -$\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_min} & int & Statically-set (i.e. absolute) mininum \\ +$\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_max} & int & Statically-set (i.e. absolute) maximum (bytes) \\ +$\mathit{RW}$ & {\tt memory/dynamic\_max} & int & Dynamic maximum (bytes) \\ +$\mathit{RO}_\mathit{run}$ & {\tt memory/actual} & int & Guest's actual usage (bytes) \\ +$\mathit{RW}$ & {\tt memory/dynamic\_min} & int & Dynamic minimum (bytes) \\ +$\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_min} & int & Statically-set (i.e. absolute) mininum (bytes) \\ $\mathit{RW}$ & {\tt VCPUs/policy} & string & the name of the VCPU scheduling policy to be applied \\ $\mathit{RW}$ & {\tt VCPUs/params} & string & string-encoded parameters passed to selected VCPU policy \\ $\mathit{RO}_\mathit{run}$ & {\tt VCPUs/number} & int & Current number of VCPUs \\ From b916a8f2796bb727be29ee42f3df272a5a00c8d2 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:40:26 +0000 Subject: [PATCH 210/282] Add VM.auto_power_on field. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 67 +++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 18e9ba8ec8..29400f01ac 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -1182,6 +1182,7 @@ $\mathit{RW}$ & {\tt name/label} & string & a human-readable name \\ $\mathit{RW}$ & {\tt name/description} & string & a notes field containg human-readable description \\ $\mathit{RW}$ & {\tt user\_version} & int & a user version number for this machine \\ $\mathit{RW}$ & {\tt is\_a\_template} & bool & true if this is a template. Template VMs can never be started, they are used only for cloning other VMs \\ +$\mathit{RW}$ & {\tt auto\_power\_on} & bool & true if this VM should be started automatically after host boot \\ $\mathit{RO}_\mathit{run}$ & {\tt resident\_on} & host ref & the host the VM is currently resident on \\ $\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_max} & int & Statically-set (i.e. absolute) maximum (bytes) \\ $\mathit{RW}$ & {\tt memory/dynamic\_max} & int & Dynamic maximum (bytes) \\ @@ -1898,6 +1899,72 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_auto\_power\_on} + +{\bf Overview:} +Get the auto\_power\_on field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} bool get_auto_power_on (session_id s, VM ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +bool +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_auto\_power\_on} + +{\bf Overview:} +Set the auto\_power\_on field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} void set_auto_power_on (session_id s, VM ref self, bool value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +{\tt bool } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} From 76b9ef8804d5629b3317208e9807c1a26cbc5f6c Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:42:28 +0000 Subject: [PATCH 211/282] Add extra detail to the VM.destroy description. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 29400f01ac..6c039a28b4 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -4073,7 +4073,7 @@ reference to the newly created object \subsubsection{RPC name:~destroy} {\bf Overview:} -Destroy the specified VM instance. +Destroy the specified VM. The VM is completely removed from the system. This function can only be called when the VM is in the Halted State. \noindent {\bf Signature:} \begin{verbatim} void destroy (session_id s, VM ref self)\end{verbatim} From af87afdaafdc8c2ee347f9ff0b5b64944136a664 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 15:45:09 +0000 Subject: [PATCH 212/282] Added VBD.type field (CD or Disk). Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 6c039a28b4..80ecd56210 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -263,6 +263,16 @@ The following enumeration types are used: \hline \end{longtable} +\vspace{1cm} +\begin{longtable}{|ll|} +\hline +{\tt enum vbd\_type} & \\ +\hline +\hspace{0.5cm}{\tt CD} & VBD will appear to guest as CD \\ +\hspace{0.5cm}{\tt Disk} & VBD will appear to guest as disk \\ +\hline +\end{longtable} + \vspace{1cm} \begin{longtable}{|ll|} \hline @@ -8635,6 +8645,7 @@ $\mathit{RW}$ & {\tt VM} & VM ref & the virtual machine \\ $\mathit{RW}$ & {\tt VDI} & VDI ref & the virtual disk \\ $\mathit{RW}$ & {\tt device} & string & device seen by the guest e.g. hda1 \\ $\mathit{RW}$ & {\tt mode} & vbd\_mode & the mode the disk should be mounted with \\ +$\mathit{RW}$ & {\tt type} & vbd\_type & how the VBD will appear to the guest (e.g. disk or CD) \\ $\mathit{RW}$ & {\tt driver} & driver\_type & the style of driver \\ $\mathit{RO}_\mathit{run}$ & {\tt io/read\_kbs} & float & Read bandwidth (KiB/s) \\ $\mathit{RO}_\mathit{run}$ & {\tt io/write\_kbs} & float & Write bandwidth (KiB/s) \\ @@ -8968,6 +8979,72 @@ void +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~get\_type} + +{\bf Overview:} +Get the type field of the given VBD. + + \noindent {\bf Signature:} +\begin{verbatim} (vbd_type) get_type (session_id s, VBD ref self)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +vbd\_type +} + + +value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_type} + +{\bf Overview:} +Set the type field of the given VBD. + + \noindent {\bf Signature:} +\begin{verbatim} void set_type (session_id s, VBD ref self, vbd_type value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VBD ref } & self & reference to the object \\ \hline + +{\tt vbd\_type } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} From a784042736e5b955e59b9690fe107457e30946b1 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 16:26:53 +0000 Subject: [PATCH 213/282] Make VM.VCPUs.number a writable field. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 36 ++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index 80ecd56210..cb3c347eaf 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -1201,7 +1201,7 @@ $\mathit{RW}$ & {\tt memory/dynamic\_min} & int & Dynamic minimum (bytes) \\ $\mathit{RO}_\mathit{ins}$ & {\tt memory/static\_min} & int & Statically-set (i.e. absolute) mininum (bytes) \\ $\mathit{RW}$ & {\tt VCPUs/policy} & string & the name of the VCPU scheduling policy to be applied \\ $\mathit{RW}$ & {\tt VCPUs/params} & string & string-encoded parameters passed to selected VCPU policy \\ -$\mathit{RO}_\mathit{run}$ & {\tt VCPUs/number} & int & Current number of VCPUs \\ +$\mathit{RW}$ & {\tt VCPUs/number} & int & Current number of VCPUs \\ $\mathit{RO}_\mathit{run}$ & {\tt VCPUs/utilisation} & (int $\rightarrow$ float) Map & Utilisation for all of guest's current VCPUs \\ $\mathit{RO}_\mathit{ins}$ & {\tt VCPUs/features/required} & (cpu\_feature) Set & CPU features the guest demands the host supports \\ $\mathit{RO}_\mathit{ins}$ & {\tt VCPUs/features/can\_use} & (cpu\_feature) Set & CPU features the guest can use if available \\ @@ -2399,6 +2399,40 @@ int value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_VCPUs\_number} + +{\bf Overview:} +Set the VCPUs/number field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} void set_VCPUs_number (session_id s, VM ref self, int value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +{\tt int } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} From 12e12aa8f9461d0aa4fbc9bf31395b49f02fef34 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 6 Dec 2006 16:33:48 +0000 Subject: [PATCH 214/282] Added VM.set_VCPUs_features_force_on, VM.set_VCPUs_features_force_off, VM.set_otherConfig. Signed-off-by: Ewan Mellor --- docs/xen-api/xenapi-datamodel.tex | 102 ++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/docs/xen-api/xenapi-datamodel.tex b/docs/xen-api/xenapi-datamodel.tex index cb3c347eaf..2facf7fec6 100644 --- a/docs/xen-api/xenapi-datamodel.tex +++ b/docs/xen-api/xenapi-datamodel.tex @@ -2561,6 +2561,40 @@ Get the VCPUs/features/force\_on field of the given VM. value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_VCPUs\_features\_force\_on} + +{\bf Overview:} +Set the VCPUs/features/force\_on field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} void set_VCPUs_features_force_on (session_id s, VM ref self, (cpu_feature) Set value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +{\tt (cpu\_feature) Set } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -2661,6 +2695,40 @@ Get the VCPUs/features/force\_off field of the given VM. value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_VCPUs\_features\_force\_off} + +{\bf Overview:} +Set the VCPUs/features/force\_off field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} void set_VCPUs_features_force_off (session_id s, VM ref self, (cpu_feature) Set value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +{\tt (cpu\_feature) Set } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} @@ -4009,6 +4077,40 @@ Get the otherConfig field of the given VM. value of the field +\vspace{0.3cm} +\vspace{0.3cm} +\vspace{0.3cm} +\subsubsection{RPC name:~set\_otherConfig} + +{\bf Overview:} +Set the otherConfig field of the given VM. + + \noindent {\bf Signature:} +\begin{verbatim} void set_otherConfig (session_id s, VM ref self, (string -> string) Map value)\end{verbatim} + + +\noindent{\bf Arguments:} + + +\vspace{0.3cm} +\begin{tabular}{|c|c|p{7cm}|} + \hline +{\bf type} & {\bf name} & {\bf description} \\ \hline +{\tt VM ref } & self & reference to the object \\ \hline + +{\tt (string $\rightarrow$ string) Map } & value & New value to set \\ \hline + +\end{tabular} + +\vspace{0.3cm} + + \noindent {\bf Return Type:} +{\tt +void +} + + + \vspace{0.3cm} \vspace{0.3cm} \vspace{0.3cm} From dc960266aaa37386c101fcb26ca30c574d15fc5f Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 10:54:43 +0000 Subject: [PATCH 215/282] [XEND] Fix reboot for HVM domains if cdrom is empty. Signed-off-by: Alastair Tse --- tools/python/xen/xend/image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 8d2aab1836..29eea9dc55 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -338,7 +338,7 @@ class HVMImageHandler(ImageHandler): for devuuid, (devtype, devinfo) in deviceConfig.items(): if devtype == 'vbd': - uname = devinfo['uname'] + uname = devinfo.get('uname') if uname is not None and 'file:' in uname: (_, vbdparam) = string.split(uname, ':', 1) if not os.path.isfile(vbdparam): From 59a3344cac1782bf3d64a5a36af49b638b7f2bf6 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 11:12:05 +0000 Subject: [PATCH 216/282] [XEND] Update vcpu_avail when parsing configuration. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 5a06f77efb..7f0da37653 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -353,10 +353,15 @@ class XendConfig(dict): if self['builder'] not in ('hvm', 'linux'): raise XendConfigError('Invalid builder configuration') + def _vcpus_sanity_check(self): + if self.get('vcpus_number') != None: + self['vcpu_avail'] = (1 << self['vcpus_number']) - 1 + def validate(self): self._memory_sanity_check() self._actions_sanity_check() self._builder_sanity_check() + self._vcpus_sanity_check() def _dominfo_to_xapi(self, dominfo): self['domid'] = dominfo['domid'] From 56e9db683be09f411dec3d0fe4f0afb433be709b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:12:52 +0000 Subject: [PATCH 217/282] [HVM] qemu: Add guest address-space mapping cache. On IA32 host or IA32 PAE host, at present, generally, we can't create an HVM guest with more than 2G memory, because generally it's almost impossible for Qemu to find a large enough and consecutive virtual address space to map an HVM guest's whole physical address space. The attached patch fixes this issue using dynamic mapping based on little blocks of memory. Signed-off-by: Jun Nakajima Signed-off-by: Dexuan Cui Signed-off-by: Keir Fraser --- tools/ioemu/target-i386-dm/cpu.h | 3 +- tools/ioemu/target-i386-dm/exec-dm.c | 17 ++- tools/ioemu/vl.c | 154 ++++++++++++++++++++------- tools/ioemu/vl.h | 20 ++++ 4 files changed, 151 insertions(+), 43 deletions(-) diff --git a/tools/ioemu/target-i386-dm/cpu.h b/tools/ioemu/target-i386-dm/cpu.h index dc016edd3e..017b8c021b 100644 --- a/tools/ioemu/target-i386-dm/cpu.h +++ b/tools/ioemu/target-i386-dm/cpu.h @@ -25,7 +25,8 @@ #ifdef TARGET_X86_64 #define TARGET_LONG_BITS 64 #else -#define TARGET_LONG_BITS 32 +/* #define TARGET_LONG_BITS 32 */ +#define TARGET_LONG_BITS 64 /* for Qemu map cache */ #endif /* target supports implicit self modifying code */ diff --git a/tools/ioemu/target-i386-dm/exec-dm.c b/tools/ioemu/target-i386-dm/exec-dm.c index be8b280dda..755d547772 100644 --- a/tools/ioemu/target-i386-dm/exec-dm.c +++ b/tools/ioemu/target-i386-dm/exec-dm.c @@ -36,6 +36,7 @@ #include "cpu.h" #include "exec-all.h" +#include "vl.h" //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH @@ -426,6 +427,12 @@ static inline int paddr_is_ram(target_phys_addr_t addr) #endif } +#if defined(__i386__) || defined(__x86_64__) +#define phys_ram_addr(x) (qemu_map_cache(x)) +#elif defined(__ia64__) +#define phys_ram_addr(x) (phys_ram_base + (x)) +#endif + void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, int len, int is_write) { @@ -438,7 +445,7 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); if (l > len) l = len; - + io_index = iomem_index(addr); if (is_write) { if (io_index) { @@ -460,9 +467,10 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } else if (paddr_is_ram(addr)) { /* Reading from RAM */ - memcpy(phys_ram_base + addr, buf, l); + ptr = phys_ram_addr(addr); + memcpy(ptr, buf, l); #ifdef __ia64__ - sync_icache((unsigned long)(phys_ram_base + addr), l); + sync_icache(ptr, l); #endif } } else { @@ -485,7 +493,8 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, } } else if (paddr_is_ram(addr)) { /* Reading from RAM */ - memcpy(buf, phys_ram_base + addr, l); + ptr = phys_ram_addr(addr); + memcpy(buf, ptr, l); } else { /* Neither RAM nor known MMIO space */ memset(buf, 0xff, len); diff --git a/tools/ioemu/vl.c b/tools/ioemu/vl.c index a2700ef313..b65f61d8df 100644 --- a/tools/ioemu/vl.c +++ b/tools/ioemu/vl.c @@ -5808,6 +5808,92 @@ int set_mm_mapping(int xc_handle, uint32_t domid, return 0; } +#if defined(__i386__) || defined(__x86_64__) +static struct map_cache *mapcache_entry; +static unsigned long nr_buckets; + +static int qemu_map_cache_init(unsigned long nr_pages) +{ + unsigned long max_pages = MAX_MCACHE_SIZE >> PAGE_SHIFT; + int i; + + if (nr_pages < max_pages) + max_pages = nr_pages; + + nr_buckets = (max_pages << PAGE_SHIFT) >> MCACHE_BUCKET_SHIFT; + + fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); + + mapcache_entry = malloc(nr_buckets * sizeof(struct map_cache)); + if (mapcache_entry == NULL) { + errno = ENOMEM; + return -1; + } + + memset(mapcache_entry, 0, nr_buckets * sizeof(struct map_cache)); + + /* + * To avoid ENOMEM from xc_map_foreign_batch() at runtime, we + * pre-fill all the map caches in advance. + */ + for (i = 0; i < nr_buckets; i++) + (void)qemu_map_cache(((target_phys_addr_t)i) << MCACHE_BUCKET_SHIFT); + + return 0; +} + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) +{ + struct map_cache *entry; + unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; + unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); + + /* For most cases (>99.9%), the page address is the same. */ + static unsigned long last_address_index = ~0UL; + static uint8_t *last_address_vaddr; + + if (address_index == last_address_index) + return last_address_vaddr + address_offset; + + entry = &mapcache_entry[address_index % nr_buckets]; + + if (entry->vaddr_base == NULL || entry->paddr_index != address_index) + { + /* We need to remap a bucket. */ + uint8_t *vaddr_base; + unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; + unsigned int i; + + if (entry->vaddr_base != NULL) { + errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); + if (errno) { + fprintf(logfile, "unmap fails %d\n", errno); + exit(-1); + } + } + + for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) + pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; + + vaddr_base = xc_map_foreign_batch( + xc_handle, domid, PROT_READ|PROT_WRITE, + pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); + if (vaddr_base == NULL) { + fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); + exit(-1); + } + + entry->vaddr_base = vaddr_base; + entry->paddr_index = address_index;; + } + + last_address_index = address_index; + last_address_vaddr = entry->vaddr_base; + + return last_address_vaddr + address_offset; +} +#endif + int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB @@ -6130,6 +6216,7 @@ int main(int argc, char **argv) break; case QEMU_OPTION_m: ram_size = atol(optarg) * 1024 * 1024; + ram_size = (uint64_t)atol(optarg) * 1024 * 1024; if (ram_size <= 0) help(); #ifndef CONFIG_DM @@ -6400,50 +6487,41 @@ int main(int argc, char **argv) shared_page_nr = nr_pages - 1; #endif +#if defined(__i386__) || defined(__x86_64__) + + if ( qemu_map_cache_init(tmp_nr_pages) ) + { + fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); + exit(-1); + } + + shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, shared_page_nr); + if (shared_page == NULL) { + fprintf(logfile, "map shared IO page returned error %d\n", errno); + exit(-1); + } + + fprintf(logfile, "shared page at pfn:%lx\n", shared_page_nr); + + buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + shared_page_nr - 2); + if (buffered_io_page == NULL) { + fprintf(logfile, "map buffered IO page returned error %d\n", errno); + exit(-1); + } + + fprintf(logfile, "buffered io page at pfn:%lx\n", shared_page_nr - 2); + +#elif defined(__ia64__) + page_array = (xen_pfn_t *)malloc(tmp_nr_pages * sizeof(xen_pfn_t)); if (page_array == NULL) { fprintf(logfile, "malloc returned error %d\n", errno); exit(-1); } -#if defined(__i386__) || defined(__x86_64__) - for ( i = 0; i < tmp_nr_pages; i++) - page_array[i] = i; - - phys_ram_base = xc_map_foreign_batch(xc_handle, domid, - PROT_READ|PROT_WRITE, page_array, - tmp_nr_pages); - if (phys_ram_base == NULL) { - fprintf(logfile, "batch map guest memory returned error %d\n", errno); - exit(-1); - } - - shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - page_array[shared_page_nr]); - if (shared_page == NULL) { - fprintf(logfile, "map shared IO page returned error %d\n", errno); - exit(-1); - } - - fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", - shared_page_nr, (uint64_t)(page_array[shared_page_nr])); - - buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, - PROT_READ|PROT_WRITE, - page_array[shared_page_nr - 2]); - if (buffered_io_page == NULL) { - fprintf(logfile, "map buffered IO page returned error %d\n", errno); - exit(-1); - } - - fprintf(logfile, "buffered io page at pfn:%lx, mfn: %"PRIx64"\n", - shared_page_nr - 2, (uint64_t)(page_array[shared_page_nr - 2])); - - free(page_array); - -#elif defined(__ia64__) - if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, IO_PAGE_START >> PAGE_SHIFT, 3) != 3) { fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); diff --git a/tools/ioemu/vl.h b/tools/ioemu/vl.h index 3df963241c..9e4d92a17b 100644 --- a/tools/ioemu/vl.h +++ b/tools/ioemu/vl.h @@ -156,6 +156,26 @@ extern void *shared_vram; extern FILE *logfile; + +#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) +#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ +#define MCACHE_BUCKET_SHIFT 16 +#elif defined(__x86_64__) +#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ +#define MCACHE_BUCKET_SHIFT 20 +#endif + +#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) + +struct map_cache { + unsigned long paddr_index; + uint8_t *vaddr_base; +}; + +uint8_t *qemu_map_cache(target_phys_addr_t phys_addr); +#endif + extern int xc_handle; extern int domid; From c8f8d49382c498f789babfbf04cb75d0692af61e Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 04:15:54 -0700 Subject: [PATCH 218/282] [IA64] implement free_irq_vector() paravirtualization This avoids a double free error message since dom0 isn't actually using the ia64_vector_mask. Signed-off-by: Akio Takebe --- .../arch/ia64/kernel/iosapic.c | 10 ++++++++ .../arch/ia64/kernel/irq_ia64.c | 7 ++++++ xen/arch/ia64/xen/hypercall.c | 23 +++++++++++++++++++ xen/include/public/physdev.h | 1 + 4 files changed, 41 insertions(+) diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c b/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c index d9b11edf96..5cbfa26004 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/iosapic.c @@ -197,6 +197,16 @@ int xen_assign_irq_vector(int irq) return irq_op.vector; } + +void xen_free_irq_vector(int vector) +{ + struct physdev_irq irq_op; + + irq_op.vector = vector; + if (HYPERVISOR_physdev_op(PHYSDEVOP_free_irq_vector, &irq_op)) + printk(KERN_WARNING "%s: xen_free_irq_vecotr fail vector=%d\n", + __FUNCTION__, vector); +} #endif /* XEN */ /* diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c index c5bba01228..495eb496f5 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/irq_ia64.c @@ -94,6 +94,13 @@ free_irq_vector (int vector) if (vector < IA64_FIRST_DEVICE_VECTOR || vector > IA64_LAST_DEVICE_VECTOR) return; +#ifdef CONFIG_XEN + if (is_running_on_xen()) { + extern void xen_free_irq_vector(int); + xen_free_irq_vector(vector); + return; + } +#endif pos = vector - IA64_FIRST_DEVICE_VECTOR; if (!test_and_clear_bit(pos, ia64_vector_mask)) printk(KERN_WARNING "%s: double free!\n", __FUNCTION__); diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index 58c6a41115..15e9f5b26b 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -454,6 +454,29 @@ static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) break; } + case PHYSDEVOP_free_irq_vector: { + struct physdev_irq irq_op; + int vector; + + ret = -EFAULT; + if ( copy_from_guest(&irq_op, arg, 1) != 0 ) + break; + + ret = -EPERM; + if ( !IS_PRIV(current->domain) ) + break; + + ret = -EINVAL; + vector = irq_op.vector; + if (vector < IA64_FIRST_DEVICE_VECTOR || + vector > IA64_LAST_DEVICE_VECTOR) + break; + + free_irq_vector(vector); + ret = 0; + break; + } + default: ret = -ENOSYS; break; diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h index 5692cee897..6f78a09fe1 100644 --- a/xen/include/public/physdev.h +++ b/xen/include/public/physdev.h @@ -152,6 +152,7 @@ DEFINE_XEN_GUEST_HANDLE(physdev_op_t); #define PHYSDEVOP_APIC_READ PHYSDEVOP_apic_read #define PHYSDEVOP_APIC_WRITE PHYSDEVOP_apic_write #define PHYSDEVOP_ASSIGN_VECTOR PHYSDEVOP_alloc_irq_vector +#define PHYSDEVOP_FREE_VECTOR PHYSDEVOP_free_irq_vector #define PHYSDEVOP_IRQ_NEEDS_UNMASK_NOTIFY XENIRQSTAT_needs_eoi #define PHYSDEVOP_IRQ_SHARED XENIRQSTAT_shared From a490953a599fdf14f3e1a9fed85949ab0c1e0b1c Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:16:17 +0000 Subject: [PATCH 219/282] [HVM] Fix reboot failure when configured 'cdrom', i.e. bug 832. Signed-off-by : Xinmei Huang --- tools/python/xen/xend/server/blkif.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/python/xen/xend/server/blkif.py b/tools/python/xen/xend/server/blkif.py index 16e2c5052d..bba11ebe1f 100644 --- a/tools/python/xen/xend/server/blkif.py +++ b/tools/python/xen/xend/server/blkif.py @@ -124,6 +124,8 @@ class BlkifController(DevController): config['dev'] = dev if typ and params: config['uname'] = typ +':' + params + else: + config['uname'] = None if mode: config['mode'] = mode if uuid: From 03b88d57897af9feaada5f5b35dec0369ce217db Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:17:28 +0000 Subject: [PATCH 220/282] [VTPM][HVM] Transmit the locality in which the command was sent in the highest 3 bits of the 4 bytes prepended to each packet. Signed-off-by: Stefan Berger --- tools/ioemu/hw/tpm_tis.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/ioemu/hw/tpm_tis.c b/tools/ioemu/hw/tpm_tis.c index a4d07bc67f..ace469f1ec 100644 --- a/tools/ioemu/hw/tpm_tis.c +++ b/tools/ioemu/hw/tpm_tis.c @@ -132,7 +132,7 @@ typedef struct TPMState { /* local prototypes */ -static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg); +static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg); static int TPM_Receive(tpmState *s, tpmBuffer *buffer); static uint32_t vtpm_instance_from_xenstore(void); static void tis_poll_timer(void *opaque); @@ -271,6 +271,8 @@ static int create_local_socket(tpmState *s, uint32_t vtpm_instance) /* * the 'write' method for sending requests to the vTPM * four bytes with the vTPM instance number are prepended to each request + * the locality in which the command was sent is transmitted in the + * highest 3 bits */ static int write_local_socket(tpmState *s, const tpmBuffer *buffer) { @@ -608,7 +610,7 @@ static void tis_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) } } if (val & STS_TPM_GO) { - n = TPM_Send(s, &s->buffer,"tpm_data_write"); + n = TPM_Send(s, &s->buffer, locty, "tpm_data_write"); if (n > 0) { /* sending of data was successful */ s->offset = 0; @@ -915,7 +917,7 @@ const static unsigned char tpm_failure[] = { /* * Send a TPM request. */ -static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg) +static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg) { int len; uint32_t size = tpm_get_size_from_buffer(buffer->buf); @@ -945,6 +947,10 @@ static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg) showBuff(buffer->buf, "To TPM"); #endif + /* transmit the locality in the highest 3 bits */ + buffer->instance[0] &= 0x1f; + buffer->instance[0] |= (locty << 5); + len = vTPMTransmit[s->Transmitlayer].write(s, buffer); if (len < 0) { s->Transmitlayer = -1; From 40574f04b42731e24cb00237b7c29bc8a5f45eab Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:18:38 +0000 Subject: [PATCH 221/282] VMXAssist cleanups Signed-off-by: Xin Li --- tools/firmware/vmxassist/head.S | 2 +- tools/firmware/vmxassist/setup.c | 4 +- tools/firmware/vmxassist/vm86.c | 203 ++++++++++++++----------------- 3 files changed, 94 insertions(+), 115 deletions(-) diff --git a/tools/firmware/vmxassist/head.S b/tools/firmware/vmxassist/head.S index a4cb614c68..7cb4ec1069 100644 --- a/tools/firmware/vmxassist/head.S +++ b/tools/firmware/vmxassist/head.S @@ -130,7 +130,7 @@ _start: clts /* setup my own stack */ - movl $stack_top - 4*4, %esp + movl $stack_top, %esp movl %esp, %ebp /* go ... */ diff --git a/tools/firmware/vmxassist/setup.c b/tools/firmware/vmxassist/setup.c index d1c47b2325..9f8928ff0d 100644 --- a/tools/firmware/vmxassist/setup.c +++ b/tools/firmware/vmxassist/setup.c @@ -125,7 +125,7 @@ setup_gdt(void) /* setup task state segment */ memset(&tss, 0, sizeof(tss)); tss.ss0 = DATA_SELECTOR; - tss.esp0 = (unsigned) stack_top - 4*4; + tss.esp0 = (unsigned) stack_top; tss.iomap_base = offsetof(struct tss, iomap); /* initialize gdt's tss selector */ @@ -258,7 +258,7 @@ setup_ctx(void) memset(c, 0, sizeof(*c)); c->eip = (unsigned long) switch_to_real_mode; - c->esp = (unsigned) stack_top - 4*4; + c->esp = (unsigned) stack_top; c->eflags = 0x2; /* no interrupts, please */ /* diff --git a/tools/firmware/vmxassist/vm86.c b/tools/firmware/vmxassist/vm86.c index 7e37de63b8..7a76ad8b15 100644 --- a/tools/firmware/vmxassist/vm86.c +++ b/tools/firmware/vmxassist/vm86.c @@ -1,6 +1,6 @@ /* * vm86.c: A vm86 emulator. The main purpose of this emulator is to do as - * little work as possible. + * little work as possible. * * Leendert van Doorn, leendert@watson.ibm.com * Copyright (c) 2005-2006, International Business Machines Corporation. @@ -52,8 +52,8 @@ char *states[] = { static char *rnames[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; #endif /* DEBUG */ -#define PDE_PS (1 << 7) -#define PT_ENTRY_PRESENT 0x1 +#define PDE_PS (1 << 7) +#define PT_ENTRY_PRESENT 0x1 /* We only support access to <=4G physical memory due to 1:1 mapping */ static uint64_t @@ -136,7 +136,7 @@ address(struct regs *regs, unsigned seg, unsigned off) } if (mode == VM86_REAL || seg > oldctx.gdtr_limit || - (mode == VM86_REAL_TO_PROTECTED && regs->cs == seg)) + (mode == VM86_REAL_TO_PROTECTED && regs->cs == seg)) return ((seg & 0xFFFF) << 4) + off; gdt_phys_base = guest_linear_to_phys(oldctx.gdtr_base); @@ -153,13 +153,13 @@ address(struct regs *regs, unsigned seg, unsigned off) seg_limit = (entry_high & 0xF0000) | (entry_low & 0xFFFF); if (entry_high & 0x8000 && - ((entry_high & 0x800000 && off >> 12 <= seg_limit) || - (!(entry_high & 0x800000) && off <= seg_limit))) + ((entry_high & 0x800000 && off >> 12 <= seg_limit) || + (!(entry_high & 0x800000) && off <= seg_limit))) return seg_base + off; panic("should never reach here in function address():\n\t" - "entry=0x%08x%08x, mode=%d, seg=0x%08x, offset=0x%08x\n", - entry_high, entry_low, mode, seg, off); + "entry=0x%08x%08x, mode=%d, seg=0x%08x, offset=0x%08x\n", + entry_high, entry_low, mode, seg, off); return 0; } @@ -172,7 +172,7 @@ trace(struct regs *regs, int adjust, char *fmt, ...) va_list ap; if ((traceset & (1 << mode)) && - (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) { + (mode == VM86_REAL_TO_PROTECTED || mode == VM86_REAL)) { /* 16-bit, seg:off addressing */ unsigned addr = address(regs, regs->cs, off); printf("0x%08x: 0x%x:0x%04x ", addr, regs->cs, off); @@ -183,7 +183,7 @@ trace(struct regs *regs, int adjust, char *fmt, ...) printf("\n"); } if ((traceset & (1 << mode)) && - (mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) { + (mode == VM86_PROTECTED_TO_REAL || mode == VM86_PROTECTED)) { /* 16-bit, gdt addressing */ unsigned addr = address(regs, regs->cs, off); printf("0x%08x: 0x%x:0x%08x ", addr, regs->cs, off); @@ -430,7 +430,7 @@ operand(unsigned prefix, struct regs *regs, unsigned modrm) case 2: return address(regs, seg, regs->edx); case 3: return address(regs, seg, regs->ebx); case 4: return address(regs, seg, - sib(regs, mod, fetch8(regs))); + sib(regs, mod, fetch8(regs))); case 5: return address(regs, seg, fetch32(regs)); case 6: return address(regs, seg, regs->esi); case 7: return address(regs, seg, regs->edi); @@ -450,7 +450,7 @@ operand(unsigned prefix, struct regs *regs, unsigned modrm) case 2: return address(regs, seg, regs->edx + disp); case 3: return address(regs, seg, regs->ebx + disp); case 4: return address(regs, seg, - sib(regs, mod, fetch8(regs))); + sib(regs, mod, fetch8(regs))); case 5: return address(regs, seg, regs->ebp + disp); case 6: return address(regs, seg, regs->esi + disp); case 7: return address(regs, seg, regs->edi + disp); @@ -507,7 +507,7 @@ operand(unsigned prefix, struct regs *regs, unsigned modrm) } } - return 0; + return 0; } /* @@ -859,7 +859,7 @@ mov_to_seg(struct regs *regs, unsigned prefix, unsigned opc) fail: printf("%s:%d: missed opcode %02x %02x\n", - __FUNCTION__, __LINE__, opc, modrm); + __FUNCTION__, __LINE__, opc, modrm); return 0; } @@ -896,11 +896,11 @@ load_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes ((entry >> (32-16)) & 0x00FF0000) | ((entry >> ( 16)) & 0x0000FFFF)); *limit = (((entry >> (48-16)) & 0x000F0000) | - ((entry ) & 0x0000FFFF)); + (entry & 0x0000FFFF)); arbytes->bytes = 0; arbytes->fields.seg_type = (entry >> (8+32)) & 0xF; /* TYPE */ - arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */ + arbytes->fields.s = (entry >> (12+32)) & 0x1; /* S */ if (arbytes->fields.s) arbytes->fields.seg_type |= 1; /* accessed */ arbytes->fields.dpl = (entry >> (13+32)) & 0x3; /* DPL */ @@ -924,7 +924,7 @@ static void load_or_clear_seg(unsigned long sel, uint32_t *base, uint32_t *limit, union vmcs_arbytes *arbytes) { if (!load_seg(sel, base, limit, arbytes)) - load_seg(0, base, limit, arbytes); + load_seg(0, base, limit, arbytes); } @@ -988,21 +988,21 @@ real_mode(struct regs *regs) panic("%%ss 0x%lx higher than 1MB", regs->uss); regs->uss = address(regs, regs->uss, 0) >> 4; } else { - regs->uss = saved_rm_regs.uss; + regs->uss = saved_rm_regs.uss; } if (regs->vds != 0) { if (regs->vds >= HIGHMEM) panic("%%ds 0x%lx higher than 1MB", regs->vds); regs->vds = address(regs, regs->vds, 0) >> 4; } else { - regs->vds = saved_rm_regs.vds; + regs->vds = saved_rm_regs.vds; } if (regs->ves != 0) { if (regs->ves >= HIGHMEM) panic("%%es 0x%lx higher than 1MB", regs->ves); regs->ves = address(regs, regs->ves, 0) >> 4; } else { - regs->ves = saved_rm_regs.ves; + regs->ves = saved_rm_regs.ves; } /* this should get us into 16-bit mode */ @@ -1029,10 +1029,7 @@ set_mode(struct regs *regs, enum vm86_mode newmode) (mode == VM86_REAL_TO_PROTECTED)) { regs->eflags &= ~EFLAGS_TF; real_mode(regs); - break; - } else if (mode == VM86_REAL) { - break; - } else + } else if (mode != VM86_REAL) panic("unexpected real mode transition"); break; @@ -1049,25 +1046,19 @@ set_mode(struct regs *regs, enum vm86_mode newmode) oldctx.fs_sel = 0; oldctx.gs_sel = 0; oldctx.ss_sel = 0; - break; - } else if (mode == VM86_REAL_TO_PROTECTED) { - break; - } else + } else if (mode != VM86_REAL_TO_PROTECTED) panic("unexpected real-to-protected mode transition"); break; case VM86_PROTECTED_TO_REAL: - if (mode == VM86_PROTECTED) { - break; - } else + if (mode != VM86_PROTECTED) panic("unexpected protected-to-real mode transition"); break; case VM86_PROTECTED: - if (mode == VM86_REAL_TO_PROTECTED) { - protected_mode(regs); - } else + if (mode != VM86_REAL_TO_PROTECTED) panic("unexpected protected mode transition"); + protected_mode(regs); break; } @@ -1081,25 +1072,19 @@ jmpl(struct regs *regs, int prefix) unsigned n = regs->eip; unsigned cs, eip; - if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */ - eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs); - cs = fetch16(regs); + eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs); + cs = fetch16(regs); - TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); + TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); - regs->cs = cs; - regs->eip = eip; + regs->cs = cs; + regs->eip = eip; + + if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ set_mode(regs, VM86_PROTECTED); - } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */ - eip = (prefix & DATA32) ? fetch32(regs) : fetch16(regs); - cs = fetch16(regs); - - TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); - - regs->cs = cs; - regs->eip = eip; + else if (mode == VM86_PROTECTED_TO_REAL)/* jump to real mode */ set_mode(regs, VM86_REAL); - } else + else panic("jmpl"); } @@ -1110,29 +1095,22 @@ jmpl_indirect(struct regs *regs, int prefix, unsigned modrm) unsigned cs, eip; unsigned addr; - addr = operand(prefix, regs, modrm); + addr = operand(prefix, regs, modrm); - if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */ - eip = (prefix & DATA32) ? read32(addr) : read16(addr); - addr += (prefix & DATA32) ? 4 : 2; - cs = read16(addr); + eip = (prefix & DATA32) ? read32(addr) : read16(addr); + addr += (prefix & DATA32) ? 4 : 2; + cs = read16(addr); - TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); + TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); - regs->cs = cs; - regs->eip = eip; + regs->cs = cs; + regs->eip = eip; + + if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ set_mode(regs, VM86_PROTECTED); - } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */ - eip = (prefix & DATA32) ? read32(addr) : read16(addr); - addr += (prefix & DATA32) ? 4 : 2; - cs = read16(addr); - - TRACE((regs, (regs->eip - n) + 1, "jmpl 0x%x:0x%x", cs, eip)); - - regs->cs = cs; - regs->eip = eip; + else if (mode == VM86_PROTECTED_TO_REAL)/* jump to real mode */ set_mode(regs, VM86_REAL); - } else + else panic("jmpl"); } @@ -1151,15 +1129,14 @@ retl(struct regs *regs, int prefix) TRACE((regs, 1, "retl (to 0x%x:0x%x)", cs, eip)); - if (mode == VM86_REAL_TO_PROTECTED) { /* jump to protected mode */ - regs->cs = cs; - regs->eip = eip; + regs->cs = cs; + regs->eip = eip; + + if (mode == VM86_REAL_TO_PROTECTED) /* jump to protected mode */ set_mode(regs, VM86_PROTECTED); - } else if (mode == VM86_PROTECTED_TO_REAL) { /* jump to real mode */ - regs->cs = cs; - regs->eip = eip; + else if (mode == VM86_PROTECTED_TO_REAL)/* jump to real mode */ set_mode(regs, VM86_REAL); - } else + else panic("retl"); } @@ -1259,8 +1236,8 @@ pushrm(struct regs *regs, int prefix, unsigned modrm) unsigned addr; unsigned data; - addr = operand(prefix, regs, modrm); - + addr = operand(prefix, regs, modrm); + if (prefix & DATA32) { data = read32(addr); push32(regs, data); @@ -1386,11 +1363,11 @@ opcode(struct regs *regs) case 0x3B: /* addr32 cmp r/m16, r16 */ if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) goto invalid; - if ((prefix & ADDR32) == 0) - goto invalid; - if (!cmp(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!cmp(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; case 0x3E: TRACE((regs, regs->eip - eip, "%%ds:")); @@ -1412,7 +1389,7 @@ opcode(struct regs *regs) prefix |= DATA32; continue; - case 0x67: + case 0x67: TRACE((regs, regs->eip - eip, "addr32")); prefix |= ADDR32; continue; @@ -1421,18 +1398,18 @@ opcode(struct regs *regs) case 0x8A: /* addr32 mov r/m8, r8 */ if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) goto invalid; - if ((prefix & ADDR32) == 0) - goto invalid; - if (!movr(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!movr(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; case 0x89: /* addr32 mov r16, r/m16 */ if (mode == VM86_PROTECTED_TO_REAL) { unsigned modrm = fetch8(regs); unsigned addr = operand(prefix, regs, modrm); unsigned val, r = (modrm >> 3) & 7; - + if (prefix & DATA32) { val = getreg16(regs, r); write32(addr, val); @@ -1447,11 +1424,11 @@ opcode(struct regs *regs) case 0x8B: /* addr32 mov r/m16, r16 */ if (mode != VM86_REAL && mode != VM86_REAL_TO_PROTECTED) goto invalid; - if ((prefix & ADDR32) == 0) - goto invalid; - if (!movr(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!movr(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; case 0x8E: /* mov r16, sreg */ if (!mov_to_seg(regs, prefix, opc)) @@ -1459,11 +1436,11 @@ opcode(struct regs *regs) return OPC_EMULATED; case 0x8F: /* addr32 pop r/m16 */ - if ((prefix & ADDR32) == 0) - goto invalid; - if (!pop(regs, prefix, opc)) - goto invalid; - return OPC_EMULATED; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!pop(regs, prefix, opc)) + goto invalid; + return OPC_EMULATED; case 0x90: /* nop */ TRACE((regs, regs->eip - eip, "nop")); @@ -1487,7 +1464,7 @@ opcode(struct regs *regs) regs->eflags |= EFLAGS_VM; return OPC_EMULATED; - case 0xA1: /* mov ax, r/m16 */ + case 0xA1: /* mov ax, r/m16 */ { int addr, data; int seg = segment(prefix, regs, regs->vds); @@ -1521,15 +1498,15 @@ opcode(struct regs *regs) return OPC_EMULATED; case 0xC6: /* addr32 movb $imm, r/m8 */ - if ((prefix & ADDR32) == 0) - goto invalid; - if (!movr(regs, prefix, opc)) - goto invalid; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!movr(regs, prefix, opc)) + goto invalid; return OPC_EMULATED; case 0xCB: /* retl */ if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + (mode == VM86_PROTECTED_TO_REAL)) { retl(regs, prefix); return OPC_INVALID; } @@ -1567,7 +1544,7 @@ opcode(struct regs *regs) case 0xEA: /* jmpl */ if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + (mode == VM86_PROTECTED_TO_REAL)) { jmpl(regs, prefix); return OPC_INVALID; } @@ -1579,7 +1556,7 @@ opcode(struct regs *regs) switch((modrm >> 3) & 7) { case 5: /* jmpl (indirect) */ if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + (mode == VM86_PROTECTED_TO_REAL)) { jmpl_indirect(regs, prefix, modrm); return OPC_INVALID; } @@ -1596,7 +1573,7 @@ opcode(struct regs *regs) case 0xEB: /* short jump */ if ((mode == VM86_REAL_TO_PROTECTED) || - (mode == VM86_PROTECTED_TO_REAL)) { + (mode == VM86_PROTECTED_TO_REAL)) { disp = (char) fetch8(regs); TRACE((regs, 2, "jmp 0x%x", regs->eip + disp)); regs->eip += disp; @@ -1619,10 +1596,10 @@ opcode(struct regs *regs) continue; case 0xF6: /* addr32 testb $imm, r/m8 */ - if ((prefix & ADDR32) == 0) - goto invalid; - if (!test(regs, prefix, opc)) - goto invalid; + if ((prefix & ADDR32) == 0) + goto invalid; + if (!test(regs, prefix, opc)) + goto invalid; return OPC_EMULATED; case 0xFA: /* cli */ @@ -1682,6 +1659,8 @@ trap(int trapno, int errno, struct regs *regs) case 1: /* Debug */ if (regs->eflags & EFLAGS_VM) { /* emulate any 8086 instructions */ + if (mode == VM86_REAL) + return; if (mode != VM86_REAL_TO_PROTECTED) panic("not in real-to-protected mode"); emulate(regs); @@ -1702,7 +1681,7 @@ trap(int trapno, int errno, struct regs *regs) default: invalid: printf("Trap (0x%x) while in %s mode\n", - trapno, regs->eflags & EFLAGS_VM ? "real" : "protected"); + trapno, regs->eflags & EFLAGS_VM ? "real" : "protected"); if (trapno == 14) printf("Page fault address 0x%x\n", get_cr2()); dump_regs(regs); From d3f023e9ade9d28b3af1e346c63f95e73ca345c0 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:22:26 +0000 Subject: [PATCH 222/282] [XEN] Make multiboot-related code more readable. Tested on i386 and x86_64 with GRUB and PXELINUX bootmanagers. From: Christoph Egger Signed-off-by: Keir Fraser --- xen/arch/x86/boot/x86_32.S | 9 ++++++--- xen/arch/x86/boot/x86_64.S | 9 ++++++--- xen/include/xen/multiboot.h | 35 ++++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S index e0f2e09643..c3466dee5f 100644 --- a/xen/arch/x86/boot/x86_32.S +++ b/xen/arch/x86/boot/x86_32.S @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -17,12 +18,14 @@ ENTRY(_stext) .align 4 /*** MULTIBOOT HEADER ****/ +#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_HEADER_MODS_ALIGNED | \ + MULTIBOOT_HEADER_WANT_MEMORY) /* Magic number indicating a Multiboot header. */ - .long 0x1BADB002 + .long MULTIBOOT_HEADER_MAGIC /* Flags to bootloader (see Multiboot spec). */ - .long 0x00000003 + .long MULTIBOOT_HEADER_FLAGS /* Checksum: must be the negated sum of the first two fields. */ - .long -0x1BADB005 + .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) not_multiboot_msg: .asciz "ERR: Not a Multiboot bootloader!" diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index 5a8a111b59..ce0e42987c 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -19,12 +20,14 @@ ENTRY(_stext) .org 0x004 /*** MULTIBOOT HEADER ****/ +#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_HEADER_MODS_ALIGNED | \ + MULTIBOOT_HEADER_WANT_MEMORY) /* Magic number indicating a Multiboot header. */ - .long 0x1BADB002 + .long MULTIBOOT_HEADER_MAGIC /* Flags to bootloader (see Multiboot spec). */ - .long 0x00000003 + .long MULTIBOOT_HEADER_FLAGS /* Checksum: must be the negated sum of the first two fields. */ - .long -0x1BADB005 + .long -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) .Lbad_cpu_msg: .asciz "ERR: Not a 64-bit CPU!" .Lbad_ldr_msg: .asciz "ERR: Not a Multiboot bootloader!" diff --git a/xen/include/xen/multiboot.h b/xen/include/xen/multiboot.h index 9473404775..86b59db1fe 100644 --- a/xen/include/xen/multiboot.h +++ b/xen/include/xen/multiboot.h @@ -18,16 +18,30 @@ #ifndef __MULTIBOOT_H__ #define __MULTIBOOT_H__ + +/* + * Multiboot header structure. + */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 +#define MULTIBOOT_HEADER_MODS_ALIGNED 0x00000001 +#define MULTIBOOT_HEADER_WANT_MEMORY 0x00000002 +#define MULTIBOOT_HEADER_HAS_VBE 0x00000004 +#define MULTIBOOT_HEADER_HAS_ADDR 0x00010000 + /* The magic number passed by a Multiboot-compliant boot loader. */ -#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 #define MBI_MEMLIMITS (1<<0) #define MBI_DRIVES (1<<1) #define MBI_CMDLINE (1<<2) #define MBI_MODULES (1<<3) +#define MBI_AOUT_SYMS (1<<4) +#define MBI_ELF_SYMS (1<<5) #define MBI_MEMMAP (1<<6) #define MBI_LOADERNAME (1<<9) +#ifndef __ASSEMBLY__ + /* The symbol table for a.out. */ typedef struct { u32 tabsize; @@ -47,16 +61,28 @@ typedef struct { /* The Multiboot information. */ typedef struct { u32 flags; + + /* Valid if flags sets MBI_MEMLIMITS */ u32 mem_lower; u32 mem_upper; + + /* Valid if flags sets MBI_DRIVES */ u32 boot_device; + + /* Valid if flags sets MBI_CMDLINE */ u32 cmdline; + + /* Valid if flags sets MBI_MODULES */ u32 mods_count; u32 mods_addr; + + /* Valid if flags sets ... */ union { - aout_symbol_table_t aout_sym; - elf_section_header_table_t elf_sec; + aout_symbol_table_t aout_sym; /* ... MBI_AOUT_SYMS */ + elf_section_header_table_t elf_sec; /* ... MBI_ELF_SYMS */ } u; + + /* Valid if flags sets MBI_MEMMAP */ u32 mmap_length; u32 mmap_addr; } multiboot_info_t; @@ -80,4 +106,7 @@ typedef struct { u32 type; } memory_map_t; + +#endif /* __ASSEMBLY__ */ + #endif /* __MULTIBOOT_H__ */ From b07ced9c1fa55ffab47e3789af1a9f9ba672ef39 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:36:26 +0000 Subject: [PATCH 223/282] [LIBXC] Add an error reporting API to the libxc library. - An 'xc_error' struct is used to pass around error details. Currently contains two members 'code' an enumeration of error types, and 'message' a free text description of the specific problem. - The xc_get_last_error() method returns a const pointer to the internal instance of this struct manged by libxc. By returning a const pointer we can add extra members to the end of the struct at any time without worrying about ABI of callers. This will let us provide more fine-grained info if needed in the future. - The xc_error instance is statically defined inside libxc and marked __thread. This ensures that errors are recorded per-thread, and that when dealing with errors we never need to call malloc - all storage needed is statically allocated. - The xc_clear_last_error() method resets any currently recorded error details - The xc_error_code_to_desc() method converts the integer error code into a generic user facing messsage. eg "Invalid kernel". Together with the 'message' field from xc_error, this provides the user visible feedback. eg "Invalid kernel: Non PAE-kernel on PAE host." - A callback can be registered with xc_set_error_handler to receive notification whenever an error is recorded, rather than querying for error details after the fact with xc_get_last_error - If built with -DDEBUG set, a default error handler will be registered which calls fprintf(stderr), thus maintaining current behaviour of logging errors to stderr during developer builds. - The python binding for libxc is updated to use xc_get_last_error to pull out error details whenever appropriate, instead of returning info based on 'errno' - The xc_set_error method is private to libxc internals, and is used for setting error details - The ERROR and PERROR macros have been updated to call xc_set_error automatically specifying XC_INTERNAL_ERROR as the error code. This gives a generic error report for all current failure points - Some uses of the ERROR macro have been replaced with explicit calls to xc_set_error to enable finer grained error reporting. In particular the code dealing with invalid kernel types uses this to report about PAE/architecture/wordsize mismatches The patch has been tested by calling xm create against a varietry of config files defining invalid kernels of various kinds. It has also been tested with libvirt talking to xend. In both cases the error messages were propagated all the way back up the stack. There is only one place where I need to do further work. The suspend & restore APIs in Xend invoke external helper programs rather than calling libxc directly. This means that error details are essentially lost. Since there is already code in XenD which scans STDERR from these programs I will investigate adapting this to extract actual error messages from these helpers. Signed-off-by: Daniel P. Berrange --- tools/libxc/xc_hvm_build.c | 16 +++-- tools/libxc/xc_linux_build.c | 12 ++-- tools/libxc/xc_load_elf.c | 95 +++++++++++++++++++++------ tools/libxc/xc_private.c | 76 ++++++++++++++++++++++ tools/libxc/xc_private.h | 19 ++---- tools/libxc/xenctrl.h | 42 ++++++++++++ tools/python/xen/lowlevel/xc/xc.c | 104 +++++++++++++++++------------- 7 files changed, 275 insertions(+), 89 deletions(-) diff --git a/tools/libxc/xc_hvm_build.c b/tools/libxc/xc_hvm_build.c index 1c038755cd..21e20ffaf9 100644 --- a/tools/libxc/xc_hvm_build.c +++ b/tools/libxc/xc_hvm_build.c @@ -285,7 +285,6 @@ static int xc_hvm_build_internal(int xc_handle, if ( setup_guest(xc_handle, domid, memsize, image, image_size, &ctxt) < 0 ) { - ERROR("Error constructing guest OS"); goto error_out; } @@ -329,26 +328,30 @@ static int parseelfimage(char *elfbase, if ( !IS_ELF(*ehdr) ) { - ERROR("Kernel image does not have an ELF header."); + xc_set_error(XC_INVALID_KERNEL, + "Kernel image does not have an ELF header."); return -EINVAL; } if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize ) { - ERROR("ELF program headers extend beyond end of image."); + xc_set_error(XC_INVALID_KERNEL, + "ELF program headers extend beyond end of image."); return -EINVAL; } if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize ) { - ERROR("ELF section headers extend beyond end of image."); + xc_set_error(XC_INVALID_KERNEL, + "ELF section headers extend beyond end of image."); return -EINVAL; } /* Find the section-header strings table. */ if ( ehdr->e_shstrndx == SHN_UNDEF ) { - ERROR("ELF image has no section-header strings table (shstrtab)."); + xc_set_error(XC_INVALID_KERNEL, + "ELF image has no section-header strings table (shstrtab)."); return -EINVAL; } shdr = (Elf32_Shdr *)(elfbase + ehdr->e_shoff + @@ -370,7 +373,8 @@ static int parseelfimage(char *elfbase, (ehdr->e_entry < kernstart) || (ehdr->e_entry > kernend) ) { - ERROR("Malformed ELF image."); + xc_set_error(XC_INVALID_KERNEL, + "Malformed ELF image."); return -EINVAL; } diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 9bd4a5e3f4..edf95c0fc0 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -120,7 +120,7 @@ static int probeimageformat(const char *image, if ( probe_elf(image, image_size, load_funcs) && probe_bin(image, image_size, load_funcs) ) { - ERROR( "Unrecognized image format" ); + xc_set_error(XC_INVALID_KERNEL, "Not a valid ELF or raw kernel image"); return -EINVAL; } @@ -618,17 +618,20 @@ static int compat_check(int xc_handle, struct domain_setup_info *dsi) xen_capabilities_info_t xen_caps = ""; if (xc_version(xc_handle, XENVER_capabilities, &xen_caps) != 0) { - ERROR("Cannot determine host capabilities."); + xc_set_error(XC_INVALID_KERNEL, + "Cannot determine host capabilities."); return 0; } if (strstr(xen_caps, "xen-3.0-x86_32p")) { if (dsi->pae_kernel == PAEKERN_no) { - ERROR("Non PAE-kernel on PAE host."); + xc_set_error(XC_INVALID_KERNEL, + "Non PAE-kernel on PAE host."); return 0; } } else if (dsi->pae_kernel != PAEKERN_no) { - ERROR("PAE-kernel on non-PAE host."); + xc_set_error(XC_INVALID_KERNEL, + "PAE-kernel on non-PAE host."); return 0; } @@ -1141,7 +1144,6 @@ static int xc_linux_build_internal(int xc_handle, console_evtchn, console_mfn, features_bitmap) < 0 ) { - ERROR("Error constructing guest OS"); goto error_out; } diff --git a/tools/libxc/xc_load_elf.c b/tools/libxc/xc_load_elf.c index 9ca9759398..f8a28fb83c 100644 --- a/tools/libxc/xc_load_elf.c +++ b/tools/libxc/xc_load_elf.c @@ -29,20 +29,46 @@ loadelfsymtab( */ #if defined(__ia64__) #define ELFCLASS ELFCLASS64 +#define ELFCLASS_DESC "64-bit" + #define ELFDATA ELFDATA2LSB +#define ELFDATA_DESC "Little-Endian" + #define ELFMACHINE EM_IA_64 +#define ELFMACHINE_DESC "ia64" + + #elif defined(__i386__) #define ELFCLASS ELFCLASS32 +#define ELFCLASS_DESC "32-bit" + #define ELFDATA ELFDATA2LSB +#define ELFDATA_DESC "Little-Endian" + #define ELFMACHINE EM_386 +#define ELFMACHINE_DESC "i386" + + #elif defined(__x86_64__) #define ELFCLASS ELFCLASS64 +#define ELFCLASS_DESC "64-bit" + #define ELFDATA ELFDATA2LSB +#define ELFDATA_DESC "Little-Endian" + #define ELFMACHINE EM_X86_64 +#define ELFMACHINE_DESC "x86_64" + + #elif defined(__powerpc__) #define ELFCLASS ELFCLASS64 +#define ELFCLASS_DESC "64-bit" + #define ELFDATA ELFDATA2MSB +#define ELFDATA_DESC "Big-Endian" + #define ELFMACHINE EM_PPC64 +#define ELFMACHINE_DESC "ppc64" #endif int probe_elf(const char *image, @@ -231,7 +257,8 @@ unsigned long long xen_elfnote_numeric(struct domain_setup_info *dsi, *defined = 1; return *(uint64_t*)ELFNOTE_DESC(note); default: - ERROR("elfnotes: unknown data size %#x for numeric type note %#x\n", + xc_set_error(XC_INVALID_KERNEL, + "elfnotes: unknown data size %#x for numeric type note %#x\n", note->descsz, type); return 0; } @@ -250,35 +277,59 @@ static int parseelfimage(const char *image, if ( !IS_ELF(*ehdr) ) { - ERROR("Kernel image does not have an ELF header."); + xc_set_error(XC_INVALID_KERNEL, + "Kernel image does not have an ELF header."); return -EINVAL; } - if ( (ehdr->e_ident[EI_CLASS] != ELFCLASS) || - (ehdr->e_machine != ELFMACHINE) || - (ehdr->e_ident[EI_DATA] != ELFDATA) || - (ehdr->e_type != ET_EXEC) ) + if (ehdr->e_machine != ELFMACHINE) { - ERROR("Kernel not a Xen-compatible Elf image."); + xc_set_error(XC_INVALID_KERNEL, + "Kernel ELF architecture '%d' does not match Xen architecture '%d' (%s)", + ehdr->e_machine, ELFMACHINE, ELFMACHINE_DESC); + return -EINVAL; + } + if (ehdr->e_ident[EI_CLASS] != ELFCLASS) + { + xc_set_error(XC_INVALID_KERNEL, + "Kernel ELF wordsize '%d' does not match Xen wordsize '%d' (%s)", + ehdr->e_ident[EI_CLASS], ELFCLASS, ELFCLASS_DESC); + return -EINVAL; + } + if (ehdr->e_ident[EI_DATA] != ELFDATA) + { + xc_set_error(XC_INVALID_KERNEL, + "Kernel ELF endianness '%d' does not match Xen endianness '%d' (%s)", + ehdr->e_ident[EI_DATA], ELFDATA, ELFDATA_DESC); + return -EINVAL; + } + if (ehdr->e_type != ET_EXEC) + { + xc_set_error(XC_INVALID_KERNEL, + "Kernel ELF type '%d' does not match Xen type '%d'", + ehdr->e_type, ET_EXEC); return -EINVAL; } if ( (ehdr->e_phoff + (ehdr->e_phnum*ehdr->e_phentsize)) > image_len ) { - ERROR("ELF program headers extend beyond end of image."); + xc_set_error(XC_INVALID_KERNEL, + "ELF program headers extend beyond end of image."); return -EINVAL; } if ( (ehdr->e_shoff + (ehdr->e_shnum*ehdr->e_shentsize)) > image_len ) { - ERROR("ELF section headers extend beyond end of image."); + xc_set_error(XC_INVALID_KERNEL, + "ELF section headers extend beyond end of image."); return -EINVAL; } /* Find the section-header strings table. */ if ( ehdr->e_shstrndx == SHN_UNDEF ) { - ERROR("ELF image has no section-header strings table (shstrtab)."); + xc_set_error(XC_INVALID_KERNEL, + "ELF image has no section-header strings table (shstrtab)."); return -EINVAL; } shdr = (Elf_Shdr *)(image + ehdr->e_shoff + @@ -325,22 +376,25 @@ static int parseelfimage(const char *image, if ( ( loader == NULL || strncmp(loader, "generic", 7) ) && ( guest_os == NULL || strncmp(guest_os, "linux", 5) ) ) { - ERROR("Will only load images built for the generic loader " - "or Linux images"); + xc_set_error(XC_INVALID_KERNEL, + "Will only load images built for the generic loader " + "or Linux images"); return -EINVAL; } if ( xen_version == NULL || strncmp(xen_version, "xen-3.0", 7) ) { - ERROR("Will only load images built for Xen v3.0"); + xc_set_error(XC_INVALID_KERNEL, + "Will only load images built for Xen v3.0"); return -EINVAL; } } else { #if defined(__x86_64__) || defined(__i386__) - ERROR("Not a Xen-ELF image: " - "No ELF notes or '__xen_guest' section found."); + xc_set_error(XC_INVALID_KERNEL, + "Not a Xen-ELF image: " + "No ELF notes or '__xen_guest' section found."); return -EINVAL; #endif } @@ -396,8 +450,9 @@ static int parseelfimage(const char *image, if ( elf_pa_off_defined && !virt_base_defined ) { - ERROR("Neither ELF_PADDR_OFFSET nor VIRT_BASE found in ELF " - " notes or __xen_guest section."); + xc_set_error(XC_INVALID_KERNEL, + "Neither ELF_PADDR_OFFSET nor VIRT_BASE found in ELF " + " notes or __xen_guest section."); return -EINVAL; } @@ -409,7 +464,8 @@ static int parseelfimage(const char *image, vaddr = phdr->p_paddr - dsi->elf_paddr_offset + dsi->v_start; if ( (vaddr + phdr->p_memsz) < vaddr ) { - ERROR("ELF program header %d is too large.", h); + xc_set_error(XC_INVALID_KERNEL, + "ELF program header %d is too large.", h); return -EINVAL; } @@ -431,7 +487,8 @@ static int parseelfimage(const char *image, (dsi->v_kernentry > kernend) || (dsi->v_start > kernstart) ) { - ERROR("ELF start or entries are out of bounds."); + xc_set_error(XC_INVALID_KERNEL, + "ELF start or entries are out of bounds."); return -EINVAL; } diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index d8dbb5e0dd..3ff0b791d0 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -8,6 +8,82 @@ #include "xc_private.h" #include "xg_private.h" +#include + +static __thread xc_error last_error = { XC_ERROR_NONE, ""}; +#if DEBUG +static xc_error_handler error_handler = xc_default_error_handler; +#else +static xc_error_handler error_handler = NULL; +#endif + +void xc_default_error_handler(const xc_error const *err) +{ + const char *desc = xc_error_code_to_desc(err->code); + fprintf(stderr, "ERROR %s: %s\n", desc, err->message); +} + +const xc_error const *xc_get_last_error(void) +{ + return &last_error; +} + +void xc_clear_last_error(void) +{ + last_error.code = XC_ERROR_NONE; + last_error.message[0] = '\0'; +} + +const char *xc_error_code_to_desc(int code) +{ + /* Sync to members of xc_error_code enumeration in xenctrl.h */ + switch ( code ) + { + case XC_ERROR_NONE: + return "No error details"; + case XC_INTERNAL_ERROR: + return "Internal error"; + case XC_INVALID_KERNEL: + return "Invalid kernel"; + } + + return "Unknown error code"; +} + +xc_error_handler xc_set_error_handler(xc_error_handler handler) +{ + xc_error_handler old = error_handler; + error_handler = handler; + return old; +} + + +static void _xc_set_error(int code, const char *msg) +{ + last_error.code = code; + strncpy(last_error.message, msg, XC_MAX_ERROR_MSG_LEN - 1); + last_error.message[XC_MAX_ERROR_MSG_LEN-1] = '\0'; +} + +void xc_set_error(int code, const char *fmt, ...) +{ + int saved_errno = errno; + char msg[XC_MAX_ERROR_MSG_LEN]; + va_list args; + + va_start(args, fmt); + vsnprintf(msg, XC_MAX_ERROR_MSG_LEN-1, fmt, args); + msg[XC_MAX_ERROR_MSG_LEN-1] = '\0'; + va_end(args); + + _xc_set_error(code, msg); + + errno = saved_errno; + + if ( error_handler != NULL ) + error_handler(&last_error); +} + int lock_pages(void *addr, size_t len) { int e = 0; diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h index 20f7a9b445..2ddec3f988 100644 --- a/tools/libxc/xc_private.h +++ b/tools/libxc/xc_private.h @@ -59,24 +59,15 @@ #define PPRINTF(_f, _a...) #endif -#define ERROR(_m, _a...) \ -do { \ - int __saved_errno = errno; \ - DPRINTF("ERROR: " _m "\n" , ## _a ); \ - errno = __saved_errno; \ -} while (0) +void xc_set_error(int code, const char *fmt, ...); + +#define ERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m , ## _a ) +#define PERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m " (%d = %s)", \ + _m , ## _a , errno, strerror(errno)) int lock_pages(void *addr, size_t len); void unlock_pages(void *addr, size_t len); -#define PERROR(_m, _a...) \ -do { \ - int __saved_errno = errno; \ - DPRINTF("ERROR: " _m " (%d = %s)\n" , ## _a , \ - __saved_errno, strerror(__saved_errno)); \ - errno = __saved_errno; \ -} while (0) - static inline void safe_munlock(const void *addr, size_t len) { int saved_errno = errno; diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 3904cede84..d0a9f5db97 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -682,4 +682,46 @@ int xc_hvm_set_isa_irq_level( int xc_hvm_set_pci_link_route( int xc_handle, domid_t dom, uint8_t link, uint8_t isa_irq); + +typedef enum { + XC_ERROR_NONE = 0, + XC_INTERNAL_ERROR = 1, + XC_INVALID_KERNEL = 2, +} xc_error_code; + +#define XC_MAX_ERROR_MSG_LEN 1024 +typedef struct { + int code; + char message[XC_MAX_ERROR_MSG_LEN]; +} xc_error; + +/* + * Return a pointer to the last error. This pointer and the + * data pointed to are only valid until the next call to + * libxc. + */ +const xc_error const *xc_get_last_error(void); + +/* + * Clear the last error + */ +void xc_clear_last_error(void); + +typedef void (*xc_error_handler)(const xc_error const* err); + +/* + * The default error handler which prints to stderr + */ +void xc_default_error_handler(const xc_error const* err); + +/* + * Convert an error code into a text description + */ +const char *xc_error_code_to_desc(int code); + +/* + * Registers a callback to handle errors + */ +xc_error_handler xc_set_error_handler(xc_error_handler handler); + #endif diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 2eb9376426..be02bf8ed8 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -29,7 +29,7 @@ #define PKG "xen.lowlevel.xc" #define CLS "xc" -static PyObject *xc_error, *zero; +static PyObject *xc_error_obj, *zero; typedef struct { PyObject_HEAD; @@ -40,6 +40,23 @@ typedef struct { static PyObject *dom_op(XcObject *self, PyObject *args, int (*fn)(int, uint32_t)); +static PyObject *pyxc_error_to_exception(void) +{ + PyObject *pyerr; + const xc_error const *err = xc_get_last_error(); + const char *desc = xc_error_code_to_desc(err->code); + + if (err->message[1]) + pyerr = Py_BuildValue("(iss)", err->code, desc, err->message); + else + pyerr = Py_BuildValue("(is)", err->code, desc); + + xc_clear_last_error(); + + PyErr_SetObject(xc_error_obj, pyerr); + + return NULL; +} static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args) { @@ -53,7 +70,7 @@ static PyObject *pyxc_domain_dumpcore(XcObject *self, PyObject *args) return NULL; if (xc_domain_dumpcore(self->xc_handle, dom, corefile) != 0) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -101,13 +118,13 @@ static PyObject *pyxc_domain_create(XcObject *self, if ( (ret = xc_domain_create(self->xc_handle, ssidref, handle, flags, &dom)) < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); return PyInt_FromLong(dom); out_exception: errno = EINVAL; - PyErr_SetFromErrno(xc_error); + PyErr_SetFromErrno(xc_error_obj); return NULL; } @@ -119,7 +136,7 @@ static PyObject *pyxc_domain_max_vcpus(XcObject *self, PyObject *args) return NULL; if (xc_domain_max_vcpus(self->xc_handle, dom, max) != 0) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -164,7 +181,7 @@ static PyObject *pyxc_vcpu_setaffinity(XcObject *self, } if ( xc_vcpu_setaffinity(self->xc_handle, dom, vcpu, cpumap) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -184,7 +201,7 @@ static PyObject *pyxc_domain_setcpuweight(XcObject *self, return NULL; if ( xc_domain_setcpuweight(self->xc_handle, dom, cpuweight) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -215,14 +232,13 @@ static PyObject *pyxc_domain_sethandle(XcObject *self, PyObject *args) } if (xc_domain_sethandle(self->xc_handle, dom, handle) < 0) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; out_exception: - errno = EINVAL; - PyErr_SetFromErrno(xc_error); + PyErr_SetFromErrno(xc_error_obj); return NULL; } @@ -251,7 +267,7 @@ static PyObject *pyxc_domain_getinfo(XcObject *self, if (nr_doms < 0) { free(info); - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); } list = PyList_New(nr_doms); @@ -306,10 +322,10 @@ static PyObject *pyxc_vcpu_getinfo(XcObject *self, rc = xc_vcpu_getinfo(self->xc_handle, dom, vcpu, &info); if ( rc < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); rc = xc_vcpu_getaffinity(self->xc_handle, dom, vcpu, &cpumap); if ( rc < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); info_dict = Py_BuildValue("{s:i,s:i,s:i,s:L,s:i}", "online", info.online, @@ -360,9 +376,7 @@ static PyObject *pyxc_linux_build(XcObject *self, ramdisk, cmdline, features, flags, store_evtchn, &store_mfn, console_evtchn, &console_mfn) != 0 ) { - if (!errno) - errno = EINVAL; - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); } return Py_BuildValue("{s:i,s:i}", "store_mfn", store_mfn, @@ -389,14 +403,14 @@ static PyObject *pyxc_hvm_build(XcObject *self, return NULL; if ( xc_hvm_build(self->xc_handle, dom, memsize, image) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); /* Set up the HVM info table. */ va_map = xc_map_foreign_range(self->xc_handle, dom, XC_PAGE_SIZE, PROT_READ | PROT_WRITE, HVM_INFO_PFN); if ( va_map == NULL ) - return PyErr_SetFromErrno(xc_error); + return PyErr_SetFromErrno(xc_error_obj); va_hvm = (struct hvm_info_table *)(va_map + HVM_INFO_OFFSET); memset(va_hvm, 0, sizeof(*va_hvm)); strncpy(va_hvm->signature, "HVM INFO", 8); @@ -431,7 +445,7 @@ static PyObject *pyxc_evtchn_alloc_unbound(XcObject *self, return NULL; if ( (port = xc_evtchn_alloc_unbound(self->xc_handle, dom, remote_dom)) < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); return PyInt_FromLong(port); } @@ -452,7 +466,7 @@ static PyObject *pyxc_physdev_pci_access_modify(XcObject *self, ret = xc_physdev_pci_access_modify( self->xc_handle, dom, bus, dev, func, enable); if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -474,7 +488,7 @@ static PyObject *pyxc_readconsolering(XcObject *self, ret = xc_readconsolering(self->xc_handle, &str, &count, clear); if ( ret < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); return PyString_FromStringAndSize(str, count); } @@ -504,7 +518,7 @@ static PyObject *pyxc_physinfo(XcObject *self) int i; if ( xc_physinfo(self->xc_handle, &info) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); *q=0; for(i=0;ixc_handle, XENVER_version, NULL); if ( xc_version(self->xc_handle, XENVER_extraversion, &xen_extra) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); if ( xc_version(self->xc_handle, XENVER_compile_info, &xen_cc) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); if ( xc_version(self->xc_handle, XENVER_changeset, &xen_chgset) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); if ( xc_version(self->xc_handle, XENVER_capabilities, &xen_caps) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); if ( xc_version(self->xc_handle, XENVER_platform_parameters, &p_parms) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); sprintf(str, "virt_start=0x%lx", p_parms.virt_start); xen_pagesize = xc_version(self->xc_handle, XENVER_pagesize, NULL); if (xen_pagesize < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); return Py_BuildValue("{s:i,s:i,s:s,s:s,s:i,s:s,s:s,s:s,s:s,s:s,s:s}", "xen_major", xen_version >> 16, @@ -593,7 +607,7 @@ static PyObject *pyxc_sedf_domain_set(XcObject *self, return NULL; if ( xc_sedf_domain_set(self->xc_handle, domid, period, slice, latency, extratime,weight) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -610,7 +624,7 @@ static PyObject *pyxc_sedf_domain_get(XcObject *self, PyObject *args) if (xc_sedf_domain_get(self->xc_handle, domid, &period, &slice,&latency,&extratime,&weight)) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i,s:i}", "domid", domid, @@ -638,7 +652,7 @@ static PyObject *pyxc_shadow_control(PyObject *self, if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL, 0, NULL) < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -668,7 +682,7 @@ static PyObject *pyxc_shadow_mem_control(PyObject *self, op = XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION; } if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, &mb, 0, NULL) < 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); mbarg = mb; return Py_BuildValue("i", mbarg); @@ -678,7 +692,7 @@ static PyObject *pyxc_sched_id_get(XcObject *self) { int sched_id; if (xc_sched_id(self->xc_handle, &sched_id) != 0) - return PyErr_SetFromErrno(xc_error); + return PyErr_SetFromErrno(xc_error_obj); return Py_BuildValue("i", sched_id); } @@ -704,7 +718,7 @@ static PyObject *pyxc_sched_credit_domain_set(XcObject *self, sdom.cap = cap; if ( xc_sched_credit_domain_set(self->xc_handle, domid, &sdom) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -719,7 +733,7 @@ static PyObject *pyxc_sched_credit_domain_get(XcObject *self, PyObject *args) return NULL; if ( xc_sched_credit_domain_get(self->xc_handle, domid, &sdom) != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); return Py_BuildValue("{s:H,s:H}", "weight", sdom.weight, @@ -735,7 +749,7 @@ static PyObject *pyxc_domain_setmaxmem(XcObject *self, PyObject *args) return NULL; if (xc_domain_setmaxmem(self->xc_handle, dom, maxmem_kb) != 0) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -762,7 +776,7 @@ static PyObject *pyxc_domain_memory_increase_reservation(XcObject *self, if ( xc_domain_memory_increase_reservation(self->xc_handle, dom, nr_extents, extent_order, address_bits, NULL) ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -784,7 +798,7 @@ static PyObject *pyxc_domain_ioport_permission(XcObject *self, ret = xc_domain_ioport_permission( self->xc_handle, dom, first_port, nr_ports, allow_access); if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -807,7 +821,7 @@ static PyObject *pyxc_domain_irq_permission(PyObject *self, ret = xc_domain_irq_permission( xc->xc_handle, dom, pirq, allow_access); if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -830,7 +844,7 @@ static PyObject *pyxc_domain_iomem_permission(PyObject *self, ret = xc_domain_iomem_permission( xc->xc_handle, dom, first_pfn, nr_pfns, allow_access); if ( ret != 0 ) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -870,7 +884,7 @@ static PyObject *dom_op(XcObject *self, PyObject *args, return NULL; if (fn(self->xc_handle, dom) != 0) - return PyErr_SetFromErrno(xc_error); + return pyxc_error_to_exception(); Py_INCREF(zero); return zero; @@ -1199,7 +1213,7 @@ static int PyXc_init(XcObject *self, PyObject *args, PyObject *kwds) { if ((self->xc_handle = xc_interface_open()) == -1) { - PyErr_SetFromErrno(xc_error); + pyxc_error_to_exception(); return -1; } @@ -1272,7 +1286,7 @@ PyMODINIT_FUNC initxc(void) if (m == NULL) return; - xc_error = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); + xc_error_obj = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); zero = PyInt_FromLong(0); /* KAF: This ensures that we get debug output in a timely manner. */ @@ -1282,8 +1296,8 @@ PyMODINIT_FUNC initxc(void) Py_INCREF(&PyXcType); PyModule_AddObject(m, CLS, (PyObject *)&PyXcType); - Py_INCREF(xc_error); - PyModule_AddObject(m, "Error", xc_error); + Py_INCREF(xc_error_obj); + PyModule_AddObject(m, "Error", xc_error_obj); /* Expose some libxc constants to Python */ PyModule_AddIntConstant(m, "XEN_SCHEDULER_SEDF", XEN_SCHEDULER_SEDF); From 4393b66b51c32e1d32a4369337bb6c2e21d0979a Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 11:41:38 +0000 Subject: [PATCH 224/282] [XEND] Fix configureBootloader to work with HTTP/SEXP. Signed-off-by: Daniel P. Berrange --- tools/python/xen/xend/XendConfig.py | 1 + tools/python/xen/xend/XendDomainInfo.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 7f0da37653..1f5571b8ba 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -680,6 +680,7 @@ class XendConfig(dict): else: self[sxp_arg] = val + _set_cfg_if_exists('bootloader') _set_cfg_if_exists('shadow_memory') _set_cfg_if_exists('security') _set_cfg_if_exists('features') diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 5488b17f8f..5fda486555 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1326,7 +1326,7 @@ class XendDomainInfo: # if we have a boot loader but no image, then we need to set things # up by running the boot loader non-interactively - if self.info.get('bootloader') and self.info.get('image'): + if self.info.get('bootloader'): self._configureBootloader() if not self._infoIsSet('image'): @@ -1532,11 +1532,17 @@ class XendDomainInfo: if not self.info.get('bootloader'): return blcfg = None + # FIXME: this assumes that we want to use the first disk device - for devuuid, (devtype, devinfo) in self.info.all_devices_sxpr(): + for (devtype, devinfo) in self.info.all_devices_sxpr(): if not devtype or not devinfo or devtype not in ('vbd', 'tap'): continue - disk = devinfo.get('uname') + disk = None + for param in devinfo: + if param[0] == 'uname': + disk = param[1] + break + if disk is None: continue fn = blkdev_uname_to_file(disk) From 99280a4af4eae8ec995fb16d1115229511186690 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Thu, 7 Dec 2006 11:43:19 +0000 Subject: [PATCH 225/282] Remove unused KEXEC_RANGE_VA_XEN. KEXEC_RANGE_VA_XEN is currently unused and there is no point in exporting it. Signed-Off-By: Magnus Damm --- Applies to xen-unstable-12756 xen/common/kexec.c | 13 +++---------- xen/include/public/kexec.h | 3 +-- 2 files changed, 4 insertions(+), 12 deletions(-) --- xen/common/kexec.c | 13 +++---------- xen/include/public/kexec.h | 3 +-- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/xen/common/kexec.c b/xen/common/kexec.c index 2f8b8e0de3..885afae80c 100644 --- a/xen/common/kexec.c +++ b/xen/common/kexec.c @@ -160,13 +160,9 @@ static int kexec_get_reserve(xen_kexec_range_t *range) extern unsigned long _text; -static int kexec_get_xen(xen_kexec_range_t *range, int get_ma) +static int kexec_get_xen(xen_kexec_range_t *range) { - if ( get_ma ) - range->start = virt_to_maddr(&_text); - else - range->start = (unsigned long) &_text; - + range->start = virt_to_maddr(&_text); range->size = (unsigned long)&_end - (unsigned long)&_text; return 0; } @@ -195,10 +191,7 @@ static int kexec_get_range(XEN_GUEST_HANDLE(void) uarg) ret = kexec_get_reserve(&range); break; case KEXEC_RANGE_MA_XEN: - ret = kexec_get_xen(&range, 1); - break; - case KEXEC_RANGE_VA_XEN: - ret = kexec_get_xen(&range, 0); + ret = kexec_get_xen(&range); break; case KEXEC_RANGE_MA_CPU: ret = kexec_get_cpu(&range); diff --git a/xen/include/public/kexec.h b/xen/include/public/kexec.h index 556aaecb3d..ca6e85b701 100644 --- a/xen/include/public/kexec.h +++ b/xen/include/public/kexec.h @@ -107,8 +107,7 @@ typedef struct xen_kexec_load { #define KEXEC_RANGE_MA_CRASH 0 /* machine address and size of crash area */ #define KEXEC_RANGE_MA_XEN 1 /* machine address and size of Xen itself */ -#define KEXEC_RANGE_VA_XEN 2 /* virtual adrress and size of Xen itself */ -#define KEXEC_RANGE_MA_CPU 3 /* machine address and size of a CPU note */ +#define KEXEC_RANGE_MA_CPU 2 /* machine address and size of a CPU note */ /* * Find the address and size of certain memory areas From df8016fc0b5f1694e0207b445780ffb2bf2155f1 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 11:45:04 +0000 Subject: [PATCH 226/282] Remove broken call to XendDomainInfo.getSsidref(), fixing the obsolete HTTP server. Signed-off-by: Ewan Mellor --- tools/python/xen/xend/server/SrvDomainDir.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index fe97b29aef..a134d5cbd9 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -165,10 +165,9 @@ class SrvDomainDir(SrvDir): req.write('
    ') for d in domains: req.write( - '
  • Domain %s: id = %s, memory = %d, ' - 'ssidref = %d.' + '
  • Domain %s: id = %s, memory = %d' % (url, d.getName(), d.getName(), d.getDomid(), - d.getMemoryTarget(), d.getSsidref())) + d.getMemoryTarget())) req.write('
  • ') req.write('
') From 3679c60f52c2dd0dd797269f7fcf61ffab8a64dd Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:46:07 +0000 Subject: [PATCH 227/282] [LIBXC] Python error extraction tweak. Signed-off-by: Keir Fraser --- tools/python/xen/lowlevel/xc/xc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index be02bf8ed8..e74a882fe0 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -46,7 +46,10 @@ static PyObject *pyxc_error_to_exception(void) const xc_error const *err = xc_get_last_error(); const char *desc = xc_error_code_to_desc(err->code); - if (err->message[1]) + if (err->code == XC_ERROR_NONE) + return PyErr_SetFromErrno(xc_error_obj); + + if (err->message[0] != '\0') pyerr = Py_BuildValue("(iss)", err->code, desc, err->message); else pyerr = Py_BuildValue("(is)", err->code, desc); From 948c26c48dfd89eaae34f29788ca63321be3b41f Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 11:50:11 +0000 Subject: [PATCH 228/282] [XM] Fix xm uptime TypeError exception. Signed-off-by: Masaki Kanno --- tools/python/xen/xm/main.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 95cbda9033..9151848d30 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -30,6 +30,7 @@ import socket import traceback import xmlrpclib import traceback +import time import datetime from select import select import xml.dom.minidom @@ -626,7 +627,13 @@ def parse_doms_info(info): def get_status(n, t, d): return DOM_STATES[t(sxp.child_value(info, n, d))] - + + start_time = get_info('start_time', float, -1) + if start_time == -1: + up_time = float(-1) + else: + up_time = time.time() - start_time + return { 'domid' : get_info('domid', str, ''), 'name' : get_info('name', str, '??'), @@ -634,7 +641,7 @@ def parse_doms_info(info): 'vcpus' : get_info('vcpus', int, 0), 'state' : get_info('state', str, ''), 'cpu_time' : get_info('cpu_time', float, 0), - 'up_time' : get_info('up_time', float, -1), + 'up_time' : up_time, 'seclabel' : security.get_security_printlabel(info), } @@ -1209,7 +1216,7 @@ def xm_uptime(args): for dom in doms: d = parse_doms_info(dom) - if d['domid'] > 0: + if int(d['domid']) > 0: uptime = int(round(d['up_time'])) else: f=open('/proc/uptime', 'r') @@ -1236,10 +1243,10 @@ def xm_uptime(args): if short_mode: now = datetime.datetime.now() upstring = now.strftime(" %H:%M:%S") + " up " + upstring - upstring += ", " + d['name'] + " (" + str(d['domid']) + ")" + upstring += ", " + d['name'] + " (" + d['domid'] + ")" else: upstring += ':%(seconds)02d' % vars() - upstring = ("%(name)-32s %(domid)3d " % d) + upstring + upstring = ("%(name)-32s %(domid)3s " % d) + upstring print upstring From 0bbc8c5421bea9062a7c8db102b635d24984a612 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 11:52:26 +0000 Subject: [PATCH 229/282] [HVM] qemu mouse: Adds support for USB mouse/tablet status check and restricts Universal Host Controller interrupt generating when received NAK in interrupt transfer. According to usb spec, USB mouse/tablet device returns NAK to host controller if its status does not alter in interrupt transfer. And UHC should leave a TD active when receiving NAK and execute this incompleted TD in a subseqent frame. UHC only generates an interrupt on complete after the TD with ICO bit is completed. This patch make UHC & USB mouse/tablet behave consistently with spec. Signed-off-by: Xinmei Huang --- tools/ioemu/hw/usb-hid.c | 19 +++++++++++++++---- tools/ioemu/hw/usb-uhci.c | 36 ++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/tools/ioemu/hw/usb-hid.c b/tools/ioemu/hw/usb-hid.c index 8fc0b744b7..60849a4ed0 100644 --- a/tools/ioemu/hw/usb-hid.c +++ b/tools/ioemu/hw/usb-hid.c @@ -39,6 +39,7 @@ typedef struct USBMouseState { int x, y; int kind; int mouse_grabbed; + int status_changed; } USBMouseState; /* mostly the same values as the Bochs USB Mouse device */ @@ -231,6 +232,7 @@ static void usb_mouse_event(void *opaque, s->dy += dy1; s->dz += dz1; s->buttons_state = buttons_state; + s->status_changed = 1; } static void usb_tablet_event(void *opaque, @@ -242,6 +244,7 @@ static void usb_tablet_event(void *opaque, s->y = y; s->dz += dz; s->buttons_state = buttons_state; + s->status_changed = 1; } static inline int int_clamp(int val, int vmin, int vmax) @@ -483,10 +486,16 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid, switch(pid) { case USB_TOKEN_IN: if (devep == 1) { - if (s->kind == USB_MOUSE) - ret = usb_mouse_poll(s, data, len); - else if (s->kind == USB_TABLET) - ret = usb_tablet_poll(s, data, len); + if (s->kind == USB_MOUSE) + ret = usb_mouse_poll(s, data, len); + else if (s->kind == USB_TABLET) + ret = usb_tablet_poll(s, data, len); + + if (!s->status_changed) + ret = USB_RET_NAK; + else + s->status_changed = 0; + } else { goto fail; } @@ -523,6 +532,7 @@ USBDevice *usb_tablet_init(void) s->dev.handle_data = usb_mouse_handle_data; s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_TABLET; + s->status_changed = 0; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); @@ -544,6 +554,7 @@ USBDevice *usb_mouse_init(void) s->dev.handle_data = usb_mouse_handle_data; s->dev.handle_destroy = usb_mouse_handle_destroy; s->kind = USB_MOUSE; + s->status_changed = 0; pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); diff --git a/tools/ioemu/hw/usb-uhci.c b/tools/ioemu/hw/usb-uhci.c index 4b8db28717..9503c51c3e 100644 --- a/tools/ioemu/hw/usb-uhci.c +++ b/tools/ioemu/hw/usb-uhci.c @@ -424,12 +424,10 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) uint8_t buf[2048]; int len, max_len, err, ret; - if (td->ctrl & TD_CTRL_IOC) { - *int_mask |= 0x01; + if (!(td->ctrl & TD_CTRL_ACTIVE)){ + ret = 1; + goto out; } - - if (!(td->ctrl & TD_CTRL_ACTIVE)) - return 1; /* TD is active */ max_len = ((td->token >> 21) + 1) & 0x7ff; @@ -467,7 +465,8 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) /* invalid pid : frame interrupted */ s->status |= UHCI_STS_HCPERR; uhci_update_irq(s); - return -1; + ret = -1; + goto out; } if (td->ctrl & TD_CTRL_IOS) td->ctrl &= ~TD_CTRL_ACTIVE; @@ -479,10 +478,12 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) len < max_len) { *int_mask |= 0x02; /* short packet: do not update QH */ - return 1; + ret = 1; + goto out; } else { /* success */ - return 0; + ret = 0; + goto out; } } else { switch(ret) { @@ -501,23 +502,34 @@ static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) } td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | (err << TD_CTRL_ERROR_SHIFT); - return 1; + ret = 1; + goto out; case USB_RET_NAK: td->ctrl |= TD_CTRL_NAK; if (pid == USB_TOKEN_SETUP) goto do_timeout; - return 1; + ret = 1; + goto out; case USB_RET_STALL: td->ctrl |= TD_CTRL_STALL; td->ctrl &= ~TD_CTRL_ACTIVE; - return 1; + ret = 1; + goto out; case USB_RET_BABBLE: td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; td->ctrl &= ~TD_CTRL_ACTIVE; /* frame interrupted */ - return -1; + ret = -1; + goto out; } } + +out: + /* If TD is inactive and IOC bit set to 1 then update int_mask */ + if ((td->ctrl & TD_CTRL_IOC) && (!(td->ctrl & TD_CTRL_ACTIVE))) { + *int_mask |= 0x01; + } + return ret; } static void uhci_frame_timer(void *opaque) From 09ddbb1ce580051ada4dd96c6667fbd3e6f10499 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 12:07:53 +0000 Subject: [PATCH 230/282] The HTTP service used for SEXPR based RPC calls currently serializes all incoming client requests. Since some requests can take non-trivial time blocking out other clients in this way has bad consequences. The attached patch makes XenD spawn a new thread to handle each incoming HTTP request. This same approach is already taken in the XML-RPC service in XenD so I don't anticipate any multi-thread issues (at least none which don't already exist). Signed-off-by: Daniel P. Berrange --- tools/python/xen/web/httpserver.py | 44 +++++++++++++++++++----------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/tools/python/xen/web/httpserver.py b/tools/python/xen/web/httpserver.py index bcf5dbd6b1..2326a2b875 100644 --- a/tools/python/xen/web/httpserver.py +++ b/tools/python/xen/web/httpserver.py @@ -264,7 +264,32 @@ class HttpServerRequest(http.HttpRequest): s += x + "/" self.write(' %s/' % (s, x)) self.write("") - + +class HttpServerClient: + + def __init__(self, server, sock, addr): + self.server = server + self.sock = sock + self.addr = addr + + def process(self): + thread = threading.Thread(target=self.doProcess) + thread.setDaemon(True) + thread.start() + + def doProcess(self): + try: + rp = RequestProcessor(self.server, self.sock, self.addr) + rp.process() + except SystemExit: + raise + except Exception, ex: + print 'HttpServer>processRequest> exception: ', ex + try: + self.sock.close() + except: + pass + class HttpServer: backlog = 5 @@ -286,8 +311,8 @@ class HttpServer: while not self.closed: (sock, addr) = self.accept() - self.processRequest(sock, addr) - + cl = HttpServerClient(self, sock, addr) + cl.process() def stop(self): self.close() @@ -314,19 +339,6 @@ class HttpServer: except: pass - def processRequest(self, sock, addr): - try: - rp = RequestProcessor(self, sock, addr) - rp.process() - except SystemExit: - raise - except Exception, ex: - print 'HttpServer>processRequest> exception: ', ex - try: - sock.close() - except: - pass - def getServerAddr(self): return (socket.gethostname(), self.port) From a2b0be52481960535db8749d3a148194aa749628 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 12:11:40 +0000 Subject: [PATCH 231/282] Do an explicit check for bootloader path existence prior to the one for executable permissions. Also print out the path being tested. Signed-off-by: Daniel P, Berrange --- tools/python/xen/xm/create.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index c081560f8e..aa0c03cac3 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -704,8 +704,10 @@ def configure_hvm(config_image, vals): config_image.append(['vncpasswd', vals.vncpasswd]) def run_bootloader(vals, config_image): + if not os.access(vals.bootloader, os.F_OK): + err("Bootloader '%s' does not exist" % vals.bootloader) if not os.access(vals.bootloader, os.X_OK): - err("Bootloader isn't executable") + err("Bootloader '%s' isn't executable" % vals.bootloader) if len(vals.disk) < 1: err("No disks configured and boot loader requested") (uname, dev, mode, backend) = vals.disk[0] From 504c725be09c53962aa5e5ada544895de02c1757 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 12:14:22 +0000 Subject: [PATCH 232/282] Scrub VNC passwords from the logs. Signed-off-by: Daniel P. Berrange --- tools/python/xen/xend/XendConfig.py | 37 +++++++++++++++++++++++-- tools/python/xen/xend/XendDomainInfo.py | 19 +++++++------ 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 1f5571b8ba..c8ab727d6b 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -42,6 +42,39 @@ def reverse_dict(adict): def bool0(v): return v != '0' and bool(v) +# Recursively copy a data struct, scrubbing out VNC passwords. +# Will scrub any dict entry with a key of 'vncpasswd' or any +# 2-element list whose first member is 'vncpasswd'. It will +# also scrub a string matching '(vncpasswd XYZ)'. Everything +# else is no-op passthrough +def scrub_password(data): + if type(data) == dict or type(data) == XendConfig: + scrubbed = {} + for key in data.keys(): + if key == "vncpasswd": + scrubbed[key] = "XXXXXXXX" + else: + scrubbed[key] = scrub_password(data[key]) + return scrubbed + elif type(data) == list: + if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd': + return ['vncpasswd', 'XXXXXXXX'] + else: + scrubbed = [] + for entry in data: + scrubbed.append(scrub_password(entry)) + return scrubbed + elif type(data) == tuple: + scrubbed = [] + for entry in data: + scrubbed.append(scrub_password(entry)) + return tuple(scrubbed) + elif type(data) == str: + return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data) + else: + return data + + # Mapping from XendConfig configuration keys to the old # legacy configuration keys that map directly. @@ -269,7 +302,7 @@ class XendConfig(dict): # output from xc.domain_getinfo self._dominfo_to_xapi(dominfo) - log.debug('XendConfig.init: %s' % self) + log.debug('XendConfig.init: %s' % scrub_password(self)) # validators go here self.validate() @@ -478,7 +511,7 @@ class XendConfig(dict): else: for opt, val in config[1:]: dev_info[opt] = val - log.debug("XendConfig: reading device: %s" % dev_info) + log.debug("XendConfig: reading device: %s" % scrub_password(dev_info)) # create uuid if it doesn't dev_uuid = dev_info.get('uuid', uuid.createString()) dev_info['uuid'] = dev_uuid diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 5fda486555..a86518ab40 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -40,6 +40,7 @@ from xen.util import security from xen.xend import balloon, sxp, uuid, image, arch from xen.xend import XendRoot, XendNode, XendConfig +from xen.xend.XendConfig import scrub_password from xen.xend.XendBootloader import bootloader from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices @@ -148,7 +149,7 @@ def create(config): @raise VmError: Invalid configuration or failure to start. """ - log.debug("XendDomainInfo.create(%s)", config) + log.debug("XendDomainInfo.create(%s)", scrub_password(config)) vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config)) try: vm.start() @@ -175,7 +176,7 @@ def recreate(info, priv): @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.recreate(%s)", info) + log.debug("XendDomainInfo.recreate(%s)", scrub_password(info)) assert not info['dying'] @@ -257,7 +258,7 @@ def restore(config): @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.restore(%s)", config) + log.debug("XendDomainInfo.restore(%s)", scrub_password(config)) vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config), resume = True) try: @@ -280,7 +281,7 @@ def createDormant(domconfig): @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.createDormant(%s)", domconfig) + log.debug("XendDomainInfo.createDormant(%s)", scrub_password(domconfig)) # domid does not make sense for non-running domains. domconfig.pop('domid', None) @@ -520,11 +521,11 @@ class XendDomainInfo: @param dev_config: device configuration @type dev_config: SXP object (parsed config) """ - log.debug("XendDomainInfo.device_create: %s" % dev_config) + log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config)) dev_type = sxp.name(dev_config) dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) dev_config_dict = self.info['devices'][dev_uuid][1] - log.debug("XendDomainInfo.device_create: %s" % dev_config_dict) + log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config_dict)) devid = self._createDevice(dev_type, dev_config_dict) self._waitForDevice(dev_type, devid) return self.getDeviceController(dev_type).sxpr(devid) @@ -746,7 +747,7 @@ class XendDomainInfo: to_store.update(self._vcpuDomDetails()) - log.debug("Storing domain details: %s", to_store) + log.debug("Storing domain details: %s", scrub_password(to_store)) self._writeDom(to_store) @@ -1188,7 +1189,7 @@ class XendDomainInfo: """ for (devclass, config) in self.info.get('devices', {}).values(): if devclass in XendDevices.valid_devices(): - log.info("createDevice: %s : %s" % (devclass, config)) + log.info("createDevice: %s : %s" % (devclass, scrub_password(config))) self._createDevice(devclass, config) if self.image: @@ -1667,7 +1668,7 @@ class XendDomainInfo: if not self._readVm('xend/restart_count'): to_store['xend/restart_count'] = str(0) - log.debug("Storing VM details: %s", to_store) + log.debug("Storing VM details: %s", scrub_password(to_store)) self._writeVm(to_store) self._setVmPermissions() From b744adfbba82cc16fbdd6285b068b07436e600fe Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 12:15:30 +0000 Subject: [PATCH 233/282] The new lifecycle patches in xen-unstable added 3 new operations which can be performed on domains - new, start and delete. libvirt has had no-op stub implementations of these APIs for a while & thus we'd enable their use for Xen 3.0.4 builds. The new APIs are not currently exposed via the existing SEXPR protocol, and since the new Xen-API protocol is unsupported tech-preview for 3.0.4 we don't want to re-write against that just yet. Thus the attached patch adds the 3 neccessary bindings for the SEXPR protocol to allow the lifecycle functionality to be invoked. It also allows the 'state' parameter to be specified when listing domains, so we can explicitly request inactive domains if we know we're running against a 3.0.4 era XenD Signed-off-by: Daniel P. Berrange --- tools/python/xen/xend/server/SrvDomain.py | 13 +++++++ tools/python/xen/xend/server/SrvDomainDir.py | 37 +++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index 82998e4d98..00c18c9386 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -21,6 +21,7 @@ from xen.web import http from xen.xend import sxp from xen.xend import XendDomain from xen.xend.Args import FormFn +from xen.xend.XendLogging import log from xen.web.SrvDir import SrvDir @@ -63,6 +64,18 @@ class SrvDomain(SrvDir): self.acceptCommand(req) return self.dom.shutdown(req.args['reason'][0]) + def op_delete(self, _, req): + self.acceptCommand(req) + return self.xd.domain_delete(self.dom.getName()) + + def op_start(self, _, req): + self.acceptCommand(req) + paused = False + if 'paused' in req.args and req.args['paused'] == [1]: + paused = True + log.debug("Starting domain " + self.dom.getName() + " " + str(paused)) + return self.xd.domain_start(self.dom.getName(), paused) + def op_sysrq(self, _, req): self.acceptCommand(req) return self.dom.send_sysrq(int(req.args['key'][0])) diff --git a/tools/python/xen/xend/server/SrvDomainDir.py b/tools/python/xen/xend/server/SrvDomainDir.py index a134d5cbd9..950b26316d 100644 --- a/tools/python/xen/xend/server/SrvDomainDir.py +++ b/tools/python/xen/xend/server/SrvDomainDir.py @@ -25,6 +25,8 @@ from xen.xend import XendDomain from xen.xend.XendDomainInfo import XendDomainInfo from xen.xend.Args import FormFn from xen.xend.XendError import XendError +from xen.xend.XendLogging import log +from xen.xend.XendConstants import DOM_STATE_RUNNING from xen.web.SrvDir import SrvDir from SrvDomain import SrvDomain @@ -101,6 +103,35 @@ class SrvDomainDir(SrvDir): out.close() return val + def op_new(self, _, req): + """Define a new domain. + Expects the domain config in request parameter 'config' in SXP format. + """ + ok = 0 + errmsg = '' + try: + configstring = req.args.get('config')[0] + #print 'op_create>', 'config:', configstring + pin = sxp.Parser() + pin.input(configstring) + pin.input_eof() + config = pin.get_val() + ok = 1 + except sxp.ParseError, ex: + errmsg = 'Invalid configuration ' + str(ex) + except Exception, ex: + print 'op_create> Exception in config', ex + traceback.print_exc() + errmsg = 'Configuration error ' + str(ex) + if not ok: + raise XendError(errmsg) + try: + self.xd.domain_new(config) + except Exception, ex: + print 'op_create> Exception creating domain:' + traceback.print_exc() + raise XendError("Error creating domain: " + str(ex)) + def op_restore(self, op, req): """Restore a domain from file. @@ -159,7 +190,11 @@ class SrvDomainDir(SrvDir): if detail: sxp.show(map(XendDomainInfo.sxpr, self.xd.list()), out=req) else: - sxp.show(self.xd.list_names(), out=req) + state = DOM_STATE_RUNNING + if 'state' in req.args and len(req.args['state']) > 0: + state = req.args['state'][0] + log.debug("Listing domains in state " + str(state)) + sxp.show(self.xd.list_names(state), out=req) else: domains = self.xd.list_sorted() req.write('
    ') From a1aafcf306ab3daecc10e56fd1e857417403960c Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 12:23:35 +0000 Subject: [PATCH 234/282] This patch checks the contents of XENDOMAINS_SAVE before the restore process begins, and prevents xendomains from attempting to start any domain that appears there, whether the domain started successfully or not. Signed off by: Hugh Brock --- tools/examples/init.d/xendomains | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/examples/init.d/xendomains b/tools/examples/init.d/xendomains index b3722882d6..7aca157bc9 100644 --- a/tools/examples/init.d/xendomains +++ b/tools/examples/init.d/xendomains @@ -204,12 +204,14 @@ start() return; fi + saved_domains=" " if [ "$XENDOMAINS_RESTORE" = "true" ] && contains_something "$XENDOMAINS_SAVE" then mkdir -p $(dirname "$LOCKFILE") touch $LOCKFILE echo -n "Restoring Xen domains:" + saved_domains=`ls $XENDOMAINS_SAVE` for dom in $XENDOMAINS_SAVE/*; do echo -n " ${dom##*/}" xm restore $dom @@ -234,9 +236,14 @@ start() # Create all domains with config files in XENDOMAINS_AUTO. # TODO: We should record which domain name belongs # so we have the option to selectively shut down / migrate later + # If a domain statefile from $XENDOMAINS_SAVE matches a domain name + # in $XENDOMAINS_AUTO, do not try to start that domain; if it didn't + # restore correctly it requires administrative attention. for dom in $XENDOMAINS_AUTO/*; do echo -n " ${dom##*/}" - if is_running $dom; then + shortdom=$(echo $dom | sed -n 's/^.*\/\(.*\)$/\1/p') + echo $saved_domains | grep -w $shortdom > /dev/null + if [ $? -eq 0 ] || is_running $dom; then echo -n "(skip)" else xm create --quiet --defconfig $dom From 36b68be87d2c9854681d2ad1473660f9f7f3e07e Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 05:34:07 -0700 Subject: [PATCH 235/282] [IA64] Implement irq redirection of IOSAPIC Signed-off-by: Anthony Xu --- xen/arch/ia64/vmx/mmio.c | 299 +------------------------ xen/arch/ia64/vmx/viosapic.c | 20 +- xen/arch/ia64/vmx/vlsapic.c | 323 ++++++++++++++++++++-------- xen/include/asm-ia64/viosapic.h | 1 + xen/include/asm-ia64/vlsapic.h | 11 + xen/include/asm-ia64/vmx_platform.h | 1 - xen/include/asm-ia64/vmx_vpd.h | 2 +- 7 files changed, 265 insertions(+), 392 deletions(-) diff --git a/xen/arch/ia64/vmx/mmio.c b/xen/arch/ia64/vmx/mmio.c index 7f3744ba6b..737220df8f 100644 --- a/xen/arch/ia64/vmx/mmio.c +++ b/xen/arch/ia64/vmx/mmio.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -37,22 +36,7 @@ #include #include #include - -/* -struct mmio_list *lookup_mmio(u64 gpa, struct mmio_list *mio_base) -{ - int i; - for (i=0; mio_base[i].iot != NOT_IO; i++ ) { - if ( gpa >= mio_base[i].start && gpa <= mio_base[i].end ) - return &mio_base[i]; - } - return NULL; -} -*/ - -#define PIB_LOW_HALF(ofst) !(ofst&(1<<20)) -#define PIB_OFST_INTA 0x1E0000 -#define PIB_OFST_XTP 0x1E0008 +#include #define HVM_BUFFERED_IO_RANGE_NR 1 @@ -118,87 +102,6 @@ int hvm_buffered_io_intercept(ioreq_t *p) return 1; } -static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value); - -static void pib_write(VCPU *vcpu, void *src, uint64_t pib_off, size_t s, int ma) -{ - switch (pib_off) { - case PIB_OFST_INTA: - panic_domain(NULL,"Undefined write on PIB INTA\n"); - break; - case PIB_OFST_XTP: - if ( s == 1 && ma == 4 /* UC */) { - vmx_vcpu_get_plat(vcpu)->xtp = *(uint8_t *)src; - } - else { - panic_domain(NULL,"Undefined write on PIB XTP\n"); - } - break; - default: - if ( PIB_LOW_HALF(pib_off) ) { // lower half - if ( s != 8 || ma != 0x4 /* UC */ ) { - panic_domain - (NULL,"Undefined IPI-LHF write with s %ld, ma %d!\n", s, ma); - } - else { - write_ipi(vcpu, pib_off, *(uint64_t *)src); - // TODO for SM-VP - } - } - else { // upper half - printk("IPI-UHF write %lx\n",pib_off); - panic_domain(NULL,"Not support yet for SM-VP\n"); - } - break; - } -} - -static void pib_read(VCPU *vcpu, uint64_t pib_off, void *dest, size_t s, int ma) -{ - switch (pib_off) { - case PIB_OFST_INTA: - // todo --- emit on processor system bus. - if ( s == 1 && ma == 4) { // 1 byte load - // TODO: INTA read from IOSAPIC - } - else { - panic_domain(NULL,"Undefined read on PIB INTA\n"); - } - break; - case PIB_OFST_XTP: - if ( s == 1 && ma == 4) { - *((uint8_t*)dest) = vmx_vcpu_get_plat(vcpu)->xtp; - } - else { - panic_domain(NULL,"Undefined read on PIB XTP\n"); - } - break; - default: - if ( PIB_LOW_HALF(pib_off) ) { // lower half - if ( s != 8 || ma != 4 ) { - panic_domain(NULL,"Undefined IPI-LHF read!\n"); - } - else { -#ifdef IPI_DEBUG - printk("IPI-LHF read %lx\n",pib_off); -#endif - *(uint64_t *)dest = 0; // TODO for SM-VP - } - } - else { // upper half - if ( s != 1 || ma != 4 ) { - panic_domain(NULL,"Undefined PIB-UHF read!\n"); - } - else { -#ifdef IPI_DEBUG - printk("IPI-UHF read %lx\n",pib_off); -#endif - *(uint8_t *)dest = 0; // TODO for SM-VP - } - } - break; - } -} static void low_mmio_access(VCPU *vcpu, u64 pa, u64 *val, size_t s, int dir) { @@ -283,11 +186,14 @@ static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int perfc_incra(vmx_mmio_access, iot >> 56); switch (iot) { - case GPFN_PIB: - if(!dir) - pib_write(vcpu, dest, src_pa - v_plat->pib_base, s, ma); + case GPFN_PIB: + if (ma != 4) + panic_domain(NULL, "Access PIB not with UC attribute\n"); + + if (!dir) + vlsapic_write(vcpu, src_pa, s, *dest); else - pib_read(vcpu, src_pa - v_plat->pib_base, dest, s, ma); + *dest = vlsapic_read(vcpu, src_pa, s); break; case GPFN_GFW: break; @@ -311,195 +217,6 @@ static void mmio_access(VCPU *vcpu, u64 src_pa, u64 *dest, size_t s, int ma, int return; } -/* - * Read or write data in guest virtual address mode. - */ -/* -void -memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa; - - if (!vtlb->nomap) - panic("Normal memory write shouldn't go to this point!"); - pa = PPN_2_PA(vtlb->ppn); - pa += POFFSET((u64)dest, vtlb->ps); - mmio_write (vcpu, src, pa, s, vtlb->ma); -} - - -void -memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa = (uint64_t)dest; - int ma; - - if ( pa & (1UL <<63) ) { - // UC - ma = 4; - pa <<=1; - pa >>=1; - } - else { - // WBL - ma = 0; // using WB for WBL - } - mmio_write (vcpu, src, pa, s, ma); -} - -void -memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa; - - if (!vtlb->nomap) - panic_domain(NULL,"Normal memory write shouldn't go to this point!"); - pa = PPN_2_PA(vtlb->ppn); - pa += POFFSET((u64)src, vtlb->ps); - - mmio_read(vcpu, pa, dest, s, vtlb->ma); -} - -void -memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s) -{ - uint64_t pa = (uint64_t)src; - int ma; - - if ( pa & (1UL <<63) ) { - // UC - ma = 4; - pa <<=1; - pa >>=1; - } - else { - // WBL - ma = 0; // using WB for WBL - } - mmio_read(vcpu, pa, dest, s, ma); -} -*/ - -/* - * To inject INIT to guest, we must set the PAL_INIT entry - * and set psr to switch to physical mode - */ -#define PAL_INIT_ENTRY 0x80000000ffffffa0 -#define PSR_SET_BITS (IA64_PSR_DT | IA64_PSR_IT | IA64_PSR_RT | \ - IA64_PSR_IC | IA64_PSR_RI) - -static void vmx_inject_guest_pal_init(VCPU *vcpu) -{ - REGS *regs = vcpu_regs(vcpu); - uint64_t psr = vmx_vcpu_get_psr(vcpu); - - regs->cr_iip = PAL_INIT_ENTRY; - - psr = psr & (~PSR_SET_BITS); - vmx_vcpu_set_psr(vcpu,psr); -} - -/* - * Deliver IPI message. (Only U-VP is supported now) - * offset: address offset to IPI space. - * value: deliver value. - */ -static void deliver_ipi (VCPU *vcpu, uint64_t dm, uint64_t vector) -{ -#ifdef IPI_DEBUG - printk ("deliver_ipi %lx %lx\n",dm,vector); -#endif - switch ( dm ) { - case 0: // INT - vmx_vcpu_pend_interrupt (vcpu, vector); - break; - case 2: // PMI - // TODO -- inject guest PMI - panic_domain (NULL, "Inject guest PMI!\n"); - break; - case 4: // NMI - vmx_vcpu_pend_interrupt (vcpu, 2); - break; - case 5: // INIT - vmx_inject_guest_pal_init(vcpu); - break; - case 7: // ExtINT - vmx_vcpu_pend_interrupt (vcpu, 0); - break; - case 1: - case 3: - case 6: - default: - panic_domain (NULL, "Deliver reserved IPI!\n"); - break; - } -} - -/* - * TODO: Use hash table for the lookup. - */ -static inline VCPU *lid_2_vcpu (struct domain *d, u64 id, u64 eid) -{ - int i; - VCPU *vcpu; - LID lid; - for (i=0; ivcpu[i]; - if (!vcpu) - continue; - lid.val = VCPU_LID(vcpu); - if ( lid.id == id && lid.eid == eid ) - return vcpu; - } - return NULL; -} - -/* - * execute write IPI op. - */ -static void write_ipi (VCPU *vcpu, uint64_t addr, uint64_t value) -{ - VCPU *targ; - struct domain *d=vcpu->domain; - targ = lid_2_vcpu(vcpu->domain, - ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); - if ( targ == NULL ) panic_domain (NULL,"Unknown IPI cpu\n"); - - if (!test_bit(_VCPUF_initialised, &targ->vcpu_flags)) { - struct pt_regs *targ_regs = vcpu_regs (targ); - struct vcpu_guest_context c; - - memset (&c, 0, sizeof (c)); - - if (arch_set_info_guest (targ, &c) != 0) { - printk ("arch_boot_vcpu: failure\n"); - return; - } - /* First or next rendez-vous: set registers. */ - vcpu_init_regs (targ); - targ_regs->cr_iip = d->arch.sal_data->boot_rdv_ip; - targ_regs->r1 = d->arch.sal_data->boot_rdv_r1; - - if (test_and_clear_bit(_VCPUF_down,&targ->vcpu_flags)) { - vcpu_wake(targ); - printk ("arch_boot_vcpu: vcpu %d awaken %016lx!\n", - targ->vcpu_id, targ_regs->cr_iip); - } - else - printk ("arch_boot_vcpu: huu, already awaken!"); - } - else { - int running = test_bit(_VCPUF_running,&targ->vcpu_flags); - deliver_ipi (targ, ((ipi_d_t)value).dm, - ((ipi_d_t)value).vector); - vcpu_unblock(targ); - if (running) - smp_send_event_check_cpu(targ->processor); - } - return; -} - - /* dir 1: read 0:write inst_type 0:integer 1:floating point diff --git a/xen/arch/ia64/vmx/viosapic.c b/xen/arch/ia64/vmx/viosapic.c index 49894291bb..f52a1f6590 100644 --- a/xen/arch/ia64/vmx/viosapic.c +++ b/xen/arch/ia64/vmx/viosapic.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -47,11 +46,18 @@ static void viosapic_deliver(struct viosapic *viosapic, int irq) switch ( delivery_mode ) { - // don't support interrupt direct currently case SAPIC_FIXED: + { + v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest); + vlsapic_set_irq(v, vector); + vcpu_kick(v); + break; + } case SAPIC_LOWEST_PRIORITY: { v = vlsapic_lid_to_vcpu(viosapic_domain(viosapic), dest); + if (viosapic->lowest_vcpu) + v = viosapic->lowest_vcpu; vlsapic_set_irq(v, vector); vcpu_kick(v); break; @@ -72,10 +78,10 @@ static int iosapic_get_highest_irq(struct viosapic *viosapic) { uint64_t irqs = viosapic->irr & ~viosapic->isr ; - if (irqs >> 32) - return (fls(irqs >> 32) - 1 + 32); - else - return fls(irqs) - 1; + if (irqs) + return ia64_fls(irqs); + + return -1; } @@ -327,5 +333,7 @@ void viosapic_init(struct domain *d) viosapic_reset(viosapic); + viosapic->lowest_vcpu = NULL; + viosapic->base_address = VIOSAPIC_DEFAULT_BASE_ADDRESS; } diff --git a/xen/arch/ia64/vmx/vlsapic.c b/xen/arch/ia64/vmx/vlsapic.c index 2fa0245099..7a495ee547 100644 --- a/xen/arch/ia64/vmx/vlsapic.c +++ b/xen/arch/ia64/vmx/vlsapic.c @@ -25,11 +25,9 @@ #include #include #include -#include #include #include #include -#include #include #include #include @@ -39,7 +37,15 @@ #include #include #include +#include #include +#include + +#ifdef IPI_DEBUG +#define IPI_DPRINTK(x...) printk(x) +#else +#define IPI_DPRINTK(x...) +#endif //u64 fire_itc; //u64 fire_itc2; @@ -116,16 +122,13 @@ static int vmx_vcpu_unpend_interrupt(VCPU *vcpu, uint8_t vector) */ static uint64_t now_itc(vtime_t *vtm) { - uint64_t guest_itc=vtm->vtm_offset+ia64_get_itc(); - - if ( vtm->vtm_local_drift ) { -// guest_itc -= vtm->vtm_local_drift; - } - if (guest_itc >= vtm->last_itc) - return guest_itc; - else - /* guest ITC backwarded due after LP switch */ - return vtm->last_itc; + uint64_t guest_itc = vtm->vtm_offset + ia64_get_itc(); + + if (guest_itc >= vtm->last_itc) + return guest_itc; + else + /* guest ITC went backward due to LP switch */ + return vtm->last_itc; } /* @@ -175,7 +178,7 @@ void vtm_init(VCPU *vcpu) { vtime_t *vtm; uint64_t itc_freq; - + vtm = &VMX(vcpu, vtm); itc_freq = local_cpu_data->itc_freq; @@ -263,76 +266,6 @@ void vtm_set_itv(VCPU *vcpu, uint64_t val) } -/* - * Update interrupt or hook the vtm timer for fire - * At this point vtm_timer should be removed if itv is masked. - */ -/* Interrupt must be disabled at this point */ -/* -void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm) -{ - uint64_t cur_itc,vitm,vitv; - uint64_t expires; - long diff_now, diff_last; - uint64_t spsr; - - vitv = VCPU(vcpu, itv); - if ( ITV_IRQ_MASK(vitv) ) { - return; - } - - vitm =VCPU(vcpu, itm); - local_irq_save(spsr); - cur_itc =now_itc(vtm); - diff_last = vtm->last_itc - vitm; - diff_now = cur_itc - vitm; - - if ( diff_last >= 0 ) { - // interrupt already fired. - stop_timer(&vtm->vtm_timer); - } - else if ( diff_now >= 0 ) { - // ITV is fired. - vmx_vcpu_pend_interrupt(vcpu, vitv&0xff); - } -*/ - /* Both last_itc & cur_itc < itm, wait for fire condition */ -/* else { - expires = NOW() + cycle_to_ns(0-diff_now) + TIMER_SLOP; - set_timer(&vtm->vtm_timer, expires); - } - local_irq_restore(spsr); -} - */ - -/* - * Action for vtm when the domain is scheduled out. - * Remove the timer for vtm. - */ -/* -void vtm_domain_out(VCPU *vcpu) -{ - if(!is_idle_domain(vcpu->domain)) - stop_timer(&vcpu->arch.arch_vmx.vtm.vtm_timer); -} - */ -/* - * Action for vtm when the domain is scheduled in. - * Fire vtm IRQ or add the timer for vtm. - */ -/* -void vtm_domain_in(VCPU *vcpu) -{ - vtime_t *vtm; - - if(!is_idle_domain(vcpu->domain)) { - vtm=&(vcpu->arch.arch_vmx.vtm); - vtm_interruption_update(vcpu, vtm); - } -} - */ - - void vlsapic_reset(VCPU *vcpu) { int i; @@ -350,6 +283,7 @@ void vlsapic_reset(VCPU *vcpu) VCPU(vcpu, lrr0) = 0x10000; // default reset value? VCPU(vcpu, lrr1) = 0x10000; // default reset value? update_vhpi(vcpu, NULL_VECTOR); + VLSAPIC_XTP(vcpu) = 0x80; // disabled for ( i=0; i<4; i++) { VLSAPIC_INSVC(vcpu,i) = 0; } @@ -367,7 +301,7 @@ static __inline__ int highest_bits(uint64_t *dat) { uint64_t bits, bitnum; int i; - + /* loop for all 256 bits */ for ( i=3; i >= 0 ; i -- ) { bits = dat[i]; @@ -411,12 +345,6 @@ static int is_higher_class(int pending, int mic) { return ( (pending >> 4) > mic ); } -#if 0 -static int is_invalid_irq(int vec) -{ - return (vec == 1 || ((vec <= 14 && vec >= 3))); -} -#endif //shadow it due to no use currently #define IRQ_NO_MASKED 0 #define IRQ_MASKED_BY_VTPR 1 @@ -427,7 +355,7 @@ static int _xirq_masked(VCPU *vcpu, int h_pending, int h_inservice) { tpr_t vtpr; - + vtpr.val = VCPU(vcpu, tpr); if ( h_inservice == NMI_VECTOR ) { @@ -467,7 +395,7 @@ _xirq_masked(VCPU *vcpu, int h_pending, int h_inservice) static int irq_masked(VCPU *vcpu, int h_pending, int h_inservice) { int mask; - + mask = _xirq_masked(vcpu, h_pending, h_inservice); return mask; } @@ -655,4 +583,213 @@ struct vcpu * vlsapic_lid_to_vcpu(struct domain *d, uint16_t dest) return v; } return NULL; -} +} + + +/* + * To inject INIT to guest, we must set the PAL_INIT entry + * and set psr to switch to physical mode + */ +#define PAL_INIT_ENTRY 0x80000000ffffffa0 +#define PSR_SET_BITS (IA64_PSR_DT | IA64_PSR_IT | IA64_PSR_RT | \ + IA64_PSR_IC | IA64_PSR_RI) + +static void vmx_inject_guest_pal_init(VCPU *vcpu) +{ + REGS *regs = vcpu_regs(vcpu); + uint64_t psr = vmx_vcpu_get_psr(vcpu); + + regs->cr_iip = PAL_INIT_ENTRY; + + psr = psr & ~PSR_SET_BITS; + vmx_vcpu_set_psr(vcpu, psr); +} + + +/* + * Deliver IPI message. (Only U-VP is supported now) + * offset: address offset to IPI space. + * value: deliver value. + */ +static void vlsapic_deliver_ipi(VCPU *vcpu, uint64_t dm, uint64_t vector) +{ + IPI_DPRINTK("deliver_ipi %lx %lx\n", dm, vector); + + switch (dm) { + case SAPIC_FIXED: // INT + vmx_vcpu_pend_interrupt(vcpu, vector); + break; + case SAPIC_PMI: + // TODO -- inject guest PMI + panic_domain(NULL, "Inject guest PMI!\n"); + break; + case SAPIC_NMI: + vmx_vcpu_pend_interrupt(vcpu, 2); + break; + case SAPIC_INIT: + vmx_inject_guest_pal_init(vcpu); + break; + case SAPIC_EXTINT: // ExtINT + vmx_vcpu_pend_interrupt(vcpu, 0); + break; + default: + panic_domain(NULL, "Deliver reserved IPI!\n"); + break; + } +} + +/* + * TODO: Use hash table for the lookup. + */ +static inline VCPU *lid_to_vcpu(struct domain *d, uint8_t id, uint8_t eid) +{ + VCPU *v; + LID lid; + + for_each_vcpu(d, v) { + lid.val = VCPU_LID(v); + if (lid.id == id && lid.eid == eid) + return v; + } + return NULL; +} + + +/* + * execute write IPI op. + */ +static void vlsapic_write_ipi(VCPU *vcpu, uint64_t addr, uint64_t value) +{ + VCPU *targ; + struct domain *d = vcpu->domain; + + targ = lid_to_vcpu(vcpu->domain, ((ipi_a_t)addr).id, ((ipi_a_t)addr).eid); + if (targ == NULL) + panic_domain(NULL, "Unknown IPI cpu\n"); + + if (!test_bit(_VCPUF_initialised, &targ->vcpu_flags)) { + struct pt_regs *targ_regs = vcpu_regs(targ); + struct vcpu_guest_context c; + + memset (&c, 0, sizeof(c)); + + if (arch_set_info_guest(targ, &c) != 0) { + printk("arch_boot_vcpu: failure\n"); + return; + } + /* First or next rendez-vous: set registers. */ + vcpu_init_regs(targ); + targ_regs->cr_iip = d->arch.sal_data->boot_rdv_ip; + targ_regs->r1 = d->arch.sal_data->boot_rdv_r1; + + if (test_and_clear_bit(_VCPUF_down,&targ->vcpu_flags)) { + vcpu_wake(targ); + printk("arch_boot_vcpu: vcpu %d awaken %016lx!\n", + targ->vcpu_id, targ_regs->cr_iip); + } else { + printk("arch_boot_vcpu: huh, already awake!"); + } + } else { + int running = test_bit(_VCPUF_running, &targ->vcpu_flags); + vlsapic_deliver_ipi(targ, ((ipi_d_t)value).dm, + ((ipi_d_t)value).vector); + vcpu_unblock(targ); + if (running) + smp_send_event_check_cpu(targ->processor); + } + return; +} + + +unsigned long vlsapic_read(struct vcpu *v, + unsigned long addr, + unsigned long length) +{ + uint64_t result = 0; + + addr &= (PIB_SIZE - 1); + + switch (addr) { + case PIB_OFST_INTA: + if (length == 1) // 1 byte load + ; // There is no i8259, there is no INTA access + else + panic_domain(NULL,"Undefined read on PIB INTA\n"); + + break; + case PIB_OFST_XTP: + if (length == 1) { + result = VLSAPIC_XTP(v); + // printk("read xtp %lx\n", result); + } else { + panic_domain(NULL, "Undefined read on PIB XTP\n"); + } + break; + default: + if (PIB_LOW_HALF(addr)) { // lower half + if (length != 8 ) + panic_domain(NULL, "Undefined IPI-LHF read!\n"); + else + IPI_DPRINTK("IPI-LHF read %lx\n", pib_off); + } else { // upper half + IPI_DPRINTK("IPI-UHF read %lx\n", addr); + } + break; + } + return result; +} + +static void vlsapic_write_xtp(struct vcpu *v, uint8_t val) +{ + struct viosapic * viosapic; + struct vcpu *lvcpu, *vcpu; + viosapic = vcpu_viosapic(v); + lvcpu = viosapic->lowest_vcpu; + VLSAPIC_XTP(v) = val; + + for_each_vcpu(v->domain, vcpu) { + if (VLSAPIC_XTP(lvcpu) > VLSAPIC_XTP(vcpu)) + lvcpu = vcpu; + } + + if (VLSAPIC_XTP(lvcpu) & 0x80) // Disabled + lvcpu = NULL; + + viosapic->lowest_vcpu = lvcpu; +} + +void vlsapic_write(struct vcpu *v, + unsigned long addr, + unsigned long length, + unsigned long val) +{ + addr &= (PIB_SIZE - 1); + + switch (addr) { + case PIB_OFST_INTA: + panic_domain(NULL, "Undefined write on PIB INTA\n"); + break; + case PIB_OFST_XTP: + if (length == 1) { + // printk("write xtp %lx\n", val); + vlsapic_write_xtp(v, val); + } else { + panic_domain(NULL, "Undefined write on PIB XTP\n"); + } + break; + default: + if (PIB_LOW_HALF(addr)) { // lower half + if (length != 8) + panic_domain(NULL, "Undefined IPI-LHF write with size %ld!\n", + length); + else + vlsapic_write_ipi(v, addr, val); + } + else { // upper half + // printk("IPI-UHF write %lx\n",addr); + panic_domain(NULL, "No support for SM-VP yet\n"); + } + break; + } +} + diff --git a/xen/include/asm-ia64/viosapic.h b/xen/include/asm-ia64/viosapic.h index 4802279dce..fdc91d56cf 100644 --- a/xen/include/asm-ia64/viosapic.h +++ b/xen/include/asm-ia64/viosapic.h @@ -78,6 +78,7 @@ struct viosapic { uint64_t isr; /* This is used for level trigger */ uint32_t ioregsel; spinlock_t lock; + struct vcpu * lowest_vcpu; uint64_t base_address; union viosapic_rte redirtbl[VIOSAPIC_NUM_PINS]; }; diff --git a/xen/include/asm-ia64/vlsapic.h b/xen/include/asm-ia64/vlsapic.h index 8cfc1db64a..cd1eeff5ed 100644 --- a/xen/include/asm-ia64/vlsapic.h +++ b/xen/include/asm-ia64/vlsapic.h @@ -49,12 +49,21 @@ #define SAPIC_EDGE 0 #define SAPIC_LEVEL 1 +/* + * LSAPIC OFFSET + */ +#define PIB_LOW_HALF(ofst) !(ofst & (1 << 20)) +#define PIB_OFST_INTA 0x1E0000 +#define PIB_OFST_XTP 0x1E0008 + /* *Mask bit */ #define SAPIC_MASK_SHIFT 16 #define SAPIC_MASK (1 << SAPIC_MASK_SHIFT) +#define VLSAPIC_XTP(_v) VMX(_v, xtp) + extern void vtm_init(struct vcpu *vcpu); extern void vtm_set_itc(struct vcpu *vcpu, uint64_t new_itc); extern void vtm_set_itm(struct vcpu *vcpu, uint64_t val); @@ -63,5 +72,7 @@ extern void vmx_vexirq(struct vcpu *vcpu); extern void vhpi_detection(struct vcpu *vcpu); extern int vmx_vcpu_pend_interrupt(VCPU * vcpu, uint8_t vector); extern struct vcpu * vlsapic_lid_to_vcpu(struct domain *d, uint16_t dest); +extern uint64_t vlsapic_read(struct vcpu *v, uint64_t addr, uint64_t s); +extern void vlsapic_write(struct vcpu *v, uint64_t addr, uint64_t s, uint64_t val); #define vlsapic_set_irq vmx_vcpu_pend_interrupt #endif diff --git a/xen/include/asm-ia64/vmx_platform.h b/xen/include/asm-ia64/vmx_platform.h index 131e3f90f8..5c0bd4c595 100644 --- a/xen/include/asm-ia64/vmx_platform.h +++ b/xen/include/asm-ia64/vmx_platform.h @@ -28,7 +28,6 @@ typedef struct virtual_platform_def { spinlock_t buffered_io_lock; unsigned long shared_page_va; unsigned long pib_base; - unsigned char xtp; unsigned long params[HVM_NR_PARAMS]; struct mmio_list *mmio; /* One IOSAPIC now... */ diff --git a/xen/include/asm-ia64/vmx_vpd.h b/xen/include/asm-ia64/vmx_vpd.h index f6676150b2..8e4eb4f55c 100644 --- a/xen/include/asm-ia64/vmx_vpd.h +++ b/xen/include/asm-ia64/vmx_vpd.h @@ -96,9 +96,9 @@ struct arch_vmx_struct { // unsigned long rfi_iip; // unsigned long rfi_ipsr; // unsigned long rfi_ifs; -// unsigned long in_service[4]; // vLsapic inservice IRQ bits unsigned long flags; unsigned long xen_port; + unsigned char xtp; #ifdef VTI_DEBUG unsigned long ivt_current; struct ivt_debug ivt_debug[IVT_DEBUG_MAX]; From 3913c1e6b919c044fcc37b8517b79aa7c5b147de Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 05:36:30 -0700 Subject: [PATCH 236/282] [IA64] fix warnings Signed-off-by: Anthony Xu --- xen/arch/ia64/vmx/optvfault.S | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/xen/arch/ia64/vmx/optvfault.S b/xen/arch/ia64/vmx/optvfault.S index 4a268f9a5d..cadf461752 100644 --- a/xen/arch/ia64/vmx/optvfault.S +++ b/xen/arch/ia64/vmx/optvfault.S @@ -209,7 +209,10 @@ GLOBAL_ENTRY(vmx_asm_rsm) dep.z r28=4,61,3 ;; mov rr[r0]=r26 + ;; mov rr[r28]=r27 + ;; + srlz.d br.many vmx_resume_to_guest END(vmx_asm_rsm) @@ -260,9 +263,10 @@ GLOBAL_ENTRY(vmx_asm_ssm) dep.z r28=4,61,3 ;; mov rr[r0]=r26 + ;; mov rr[r28]=r27 ;; - srlz.i + srlz.d ;; vmx_asm_ssm_1: tbit.nz p6,p0=r29,IA64_PSR_I_BIT @@ -341,9 +345,10 @@ vmx_asm_mov_to_psr_back: dep.z r28=4,61,3 ;; mov rr[r0]=r26 + ;; mov rr[r28]=r27 ;; - srlz.i + srlz.d ;; vmx_asm_mov_to_psr_1: mov r20=cr.ipsr From 92b2e5f15ced138d082426d3759472a910990b27 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 05:43:04 -0700 Subject: [PATCH 237/282] [IA64] Send events to VTI domain through level triggered irq. Signed-off-by: Anthony Xu --- xen/arch/ia64/vmx/vmx_process.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/xen/arch/ia64/vmx/vmx_process.c b/xen/arch/ia64/vmx/vmx_process.c index 0aaef9a7c7..94011beb71 100644 --- a/xen/arch/ia64/vmx/vmx_process.c +++ b/xen/arch/ia64/vmx/vmx_process.c @@ -206,28 +206,14 @@ void leave_hypervisor_tail(struct pt_regs *regs) do_softirq(); local_irq_disable(); -// if (user_regs != regs) -// printk("WARNING: checking pending interrupt in nested interrupt!!!\n"); - - /* FIXME: Check event pending indicator, and set - * pending bit if necessary to inject back to guest. - * Should be careful about window between this check - * and above assist, since IOPACKET_PORT shouldn't be - * injected into vmx domain. - * - * Now hardcode the vector as 0x10 temporarily - */ -// if (event_pending(v)&&(!(VLSAPIC_INSVC(v,0)&(1UL<<0x10)))) { -// VCPU(v, irr[0]) |= 1UL << 0x10; -// v->arch.irq_new_pending = 1; -// } - if (v->vcpu_id == 0) { int callback_irq = d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; - if (callback_irq != 0) { + if (callback_irq != 0 && local_events_need_delivery()) { /* change level for para-device callback irq */ - viosapic_set_irq(d, callback_irq, local_events_need_delivery()); + /* use level irq to send discrete event */ + viosapic_set_irq(d, callback_irq, 1); + viosapic_set_irq(d, callback_irq, 0); } } From 9ca50215eebbf159c905235f4d5de945b9b446e2 Mon Sep 17 00:00:00 2001 From: Tim Deegan Date: Thu, 7 Dec 2006 13:14:44 +0000 Subject: [PATCH 238/282] [XEN] Init pae_l3_cache lock earlier In particular, before hvm_vcpu_initialise causes a CR3 update. Signed-off-by: Tim Deegan --- xen/arch/x86/domain.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 75d5284aeb..9171b394ae 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -134,6 +134,8 @@ int vcpu_initialise(struct vcpu *v) v->arch.flags = TF_kernel_mode; + pae_l3_cache_init(&v->arch.pae_l3_cache); + if ( is_hvm_domain(d) ) { if ( (rc = hvm_vcpu_initialise(v)) != 0 ) @@ -155,8 +157,6 @@ int vcpu_initialise(struct vcpu *v) v->arch.perdomain_ptes = d->arch.mm_perdomain_pt + (v->vcpu_id << GDT_LDT_VCPU_SHIFT); - pae_l3_cache_init(&v->arch.pae_l3_cache); - return 0; } From e150713e686a554fedfc97102cdc0d920d1c5bbb Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 13:47:13 +0000 Subject: [PATCH 239/282] [XEND] Fix resume for managed domains. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendCheckpoint.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/python/xen/xend/XendCheckpoint.py b/tools/python/xen/xend/XendCheckpoint.py index 707a9c5c3c..21a323cdcc 100644 --- a/tools/python/xen/xend/XendCheckpoint.py +++ b/tools/python/xen/xend/XendCheckpoint.py @@ -137,7 +137,6 @@ def restore(xd, fd, dominfo = None, paused = False): vmconfig = p.get_val() if dominfo: - dominfo.update(XendConfig(sxp_obj = vmconfig), refresh = False) dominfo.resume() else: dominfo = xd.restore_(vmconfig) From bd52f01c26803f7346e636b5cc599811050af116 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 14:03:54 +0000 Subject: [PATCH 240/282] [XEN] Early page fault handler to deal with spurious page faults. Signed-off-by: Keir Fraser --- xen/arch/x86/crash.c | 12 ++---------- xen/arch/x86/setup.c | 11 ++++++----- xen/arch/x86/traps.c | 31 +++++++++++++++++++++++++++++++ xen/arch/x86/x86_32/domain_page.c | 26 -------------------------- xen/arch/x86/x86_32/entry.S | 8 ++++++++ xen/arch/x86/x86_64/entry.S | 6 ++++++ xen/include/xen/domain_page.h | 9 --------- 7 files changed, 53 insertions(+), 50 deletions(-) diff --git a/xen/arch/x86/crash.c b/xen/arch/x86/crash.c index 3389174a7a..a5b0aeedf1 100644 --- a/xen/arch/x86/crash.c +++ b/xen/arch/x86/crash.c @@ -27,7 +27,6 @@ #include #include -#ifdef CONFIG_SMP static atomic_t waiting_for_crash_ipi; static int crash_nmi_callback(struct cpu_user_regs *regs, int cpu) @@ -71,9 +70,7 @@ static void nmi_shootdown_cpus(void) atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); /* Would it be better to replace the trap vector here? */ set_nmi_callback(crash_nmi_callback); - /* Ensure the new callback function is set before sending - * out the NMI - */ + /* Ensure the new callback function is set before sending out the NMI. */ wmb(); smp_send_nmi_allbutself(); @@ -88,7 +85,6 @@ static void nmi_shootdown_cpus(void) /* Leave the nmi callback set */ disable_local_APIC(); } -#endif static void crash_save_xen_notes(void) { @@ -102,16 +98,12 @@ static void crash_save_xen_notes(void) void machine_crash_shutdown(void) { - printk("machine_crash_shutdown: %d\n", smp_processor_id()); local_irq_disable(); -#ifdef CONFIG_SMP nmi_shootdown_cpus(); -#endif -#ifdef CONFIG_X86_IO_APIC disable_IO_APIC(); -#endif + hvm_disable(); crash_save_xen_notes(); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 391a50eb05..8d9f6f9e08 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -305,6 +305,9 @@ void __init __start_xen(multiboot_info_t *mbi) .stop_bits = 1 }; + extern void early_page_fault(void); + set_intr_gate(TRAP_page_fault, &early_page_fault); + /* Parse the command-line options. */ if ( (mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0) ) cmdline = __va(mbi->cmdline); @@ -501,21 +504,19 @@ void __init __start_xen(multiboot_info_t *mbi) kdump_start >>= PAGE_SHIFT; kdump_size >>= PAGE_SHIFT; - /* allocate pages for Kdump memory area */ + /* Allocate pages for Kdump memory area. */ k = alloc_boot_pages_at(kdump_size, kdump_start); - if ( k != kdump_start ) panic("Unable to reserve Kdump memory\n"); - /* allocate pages for relocated initial images */ + /* Allocate pages for relocated initial images. */ k = ((initial_images_end - initial_images_start) & ~PAGE_MASK) ? 1 : 0; k += (initial_images_end - initial_images_start) >> PAGE_SHIFT; k = alloc_boot_pages(k, 1); - - if ( !k ) + if ( k == 0 ) panic("Unable to allocate initial images memory\n"); move_memory(k << PAGE_SHIFT, initial_images_start, initial_images_end); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 3e6ab2856d..11960e56fb 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -935,6 +935,37 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) return 0; } +/* + * Early handler to deal with spurious page faults. For example, consider a + * routine that uses a mapping immediately after installing it (making it + * present). The CPU may speculatively execute the memory access before + * executing the PTE write. The instruction will then be marked to cause a + * page fault when it is retired, despite the fact that the PTE is present and + * correct at that point in time. + */ +asmlinkage int do_early_page_fault(struct cpu_user_regs *regs) +{ + static int stuck; + static unsigned long prev_eip, prev_cr2; + unsigned long cr2 = read_cr2(); + + BUG_ON(smp_processor_id() != 0); + + if ( (regs->eip != prev_eip) || (cr2 != prev_cr2) ) + { + prev_eip = regs->eip; + prev_cr2 = cr2; + stuck = 0; + return EXCRET_not_a_fault; + } + + if ( stuck++ == 1000 ) + panic("Early fatal page fault at %04x:%p (cr2=%p, ec=%04x)\n", + regs->cs, _p(regs->eip), _p(cr2), regs->error_code); + + return EXCRET_not_a_fault; +} + long do_fpu_taskswitch(int set) { struct vcpu *v = current; diff --git a/xen/arch/x86/x86_32/domain_page.c b/xen/arch/x86/x86_32/domain_page.c index 2b760ce704..93cd2379a7 100644 --- a/xen/arch/x86/x86_32/domain_page.c +++ b/xen/arch/x86/x86_32/domain_page.c @@ -252,29 +252,3 @@ void unmap_domain_page_global(void *va) idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT; set_bit(idx, garbage); } - -paddr_t maddr_from_mapped_domain_page(void *va) -{ - unsigned long __va = (unsigned long)va; - l2_pgentry_t *pl2e; - l1_pgentry_t *pl1e; - unsigned int idx; - struct mapcache *cache; - unsigned long mfn; - - if ( (__va >= MAPCACHE_VIRT_START) && (__va < MAPCACHE_VIRT_END) ) - { - cache = &mapcache_current_vcpu()->domain->arch.mapcache; - idx = ((unsigned long)va - MAPCACHE_VIRT_START) >> PAGE_SHIFT; - mfn = l1e_get_pfn(cache->l1tab[idx]); - } - else - { - ASSERT(__va >= IOREMAP_VIRT_START); - pl2e = virt_to_xen_l2e(__va); - pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va); - mfn = l1e_get_pfn(*pl1e); - } - - return ((paddr_t)mfn << PAGE_SHIFT) | ((unsigned long)va & ~PAGE_MASK); -} diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S index 566f4d4279..454e963fe3 100644 --- a/xen/arch/x86/x86_32/entry.S +++ b/xen/arch/x86/x86_32/entry.S @@ -536,6 +536,14 @@ ENTRY(spurious_interrupt_bug) pushl $TRAP_spurious_int<<16 jmp handle_exception +ENTRY(early_page_fault) + SAVE_ALL_NOSEGREGS(a) + movl %esp,%edx + pushl %edx + call do_early_page_fault + addl $4,%esp + jmp restore_all_xen + ENTRY(nmi) #ifdef CONFIG_X86_SUPERVISOR_MODE_KERNEL # NMI entry protocol is incompatible with guest kernel in ring 0. diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S index 87602a3d86..b28b644c33 100644 --- a/xen/arch/x86/x86_64/entry.S +++ b/xen/arch/x86/x86_64/entry.S @@ -478,6 +478,12 @@ ENTRY(double_fault) call do_double_fault ud2 +ENTRY(early_page_fault) + SAVE_ALL + movq %rsp,%rdi + call do_early_page_fault + jmp restore_all_xen + ENTRY(nmi) pushq $0 SAVE_ALL diff --git a/xen/include/xen/domain_page.h b/xen/include/xen/domain_page.h index 3f83b2a6db..7067f33ff7 100644 --- a/xen/include/xen/domain_page.h +++ b/xen/include/xen/domain_page.h @@ -34,13 +34,6 @@ void unmap_domain_page(void *va); void *map_domain_page_global(unsigned long mfn); void unmap_domain_page_global(void *va); -/* - * Convert a VA (within a page previously mapped in the context of the - * currently-executing VCPU via a call to map_domain_page(), or via a - * previous call to map_domain_page_global()) to the mapped machine address. - */ -paddr_t maddr_from_mapped_domain_page(void *va); - #define DMCACHE_ENTRY_VALID 1U #define DMCACHE_ENTRY_HELD 2U @@ -109,8 +102,6 @@ domain_mmap_cache_destroy(struct domain_mmap_cache *cache) #define map_domain_page_global(mfn) maddr_to_virt((mfn)< Date: Thu, 7 Dec 2006 14:38:16 +0000 Subject: [PATCH 241/282] [XEND] Prevent None values from appearing in Device SXP Signed-off-by: Alastair Tse --- tools/python/xen/xend/server/DevController.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xend/server/DevController.py b/tools/python/xen/xend/server/DevController.py index 646e19d9de..b8dc8f4763 100644 --- a/tools/python/xen/xend/server/DevController.py +++ b/tools/python/xen/xend/server/DevController.py @@ -226,9 +226,11 @@ class DevController: for key, val in configDict.items(): if isinstance(val, (types.ListType, types.TupleType)): for v in val: - sxpr.append([key, v]) + if v != None: + sxpr.append([key, v]) else: - sxpr.append([key, val]) + if val != None: + sxpr.append([key, val]) return sxpr def sxprs(self): From dee1d9ba0c760f68519f2354d1660f80d7447dfb Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 14:40:13 +0000 Subject: [PATCH 242/282] [XEND] Make SXP parsing re-use device_add in XendConfig This will fix the IP address configuration problem for vifs. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 38 ++++++++++++++++++----------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index c8ab727d6b..526e8836a5 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -509,14 +509,8 @@ class XendConfig(dict): log.debug("XendConfig: reading device: %s" % pci_devs) else: - for opt, val in config[1:]: - dev_info[opt] = val + self.device_add(dev_type, cfg_sxp = config, target = cfg) log.debug("XendConfig: reading device: %s" % scrub_password(dev_info)) - # create uuid if it doesn't - dev_uuid = dev_info.get('uuid', uuid.createString()) - dev_info['uuid'] = dev_uuid - cfg['devices'][dev_uuid] = (dev_type, dev_info) - # Extract missing data from configuration entries image_sxp = sxp.child_value(sxp_cfg, 'image', []) @@ -867,7 +861,8 @@ class XendConfig(dict): return sxpr - def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None): + def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None, + target = None): """Add a device configuration in SXP format or XenAPI struct format. For SXP, it could be either: @@ -882,9 +877,14 @@ class XendConfig(dict): @param cfg_sxp: SXP configuration object @type cfg_xenapi: dict @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif) + @param target: write device information to + @type target: None or a dictionary @rtype: string @return: Assigned UUID of the device. """ + if target == None: + target = self + if dev_type not in XendDevices.valid_devices() and \ dev_type not in XendDevices.pseudo_devices(): raise XendConfigError("XendConfig: %s not a valid device type" % @@ -914,15 +914,18 @@ class XendConfig(dict): except ValueError: pass # SXP has no options for this device - - def _get_config_ipaddr(config): + + # Special handling for certain device parameters. + + def _get_config_ipaddr(cfg): val = [] - for ipaddr in sxp.children(config, elt='ip'): + for ipaddr in sxp.children(cfg, elt='ip'): val.append(sxp.child0(ipaddr)) return val if dev_type == 'vif' and 'ip' in dev_info: dev_info['ip'] = _get_config_ipaddr(config) + log.debug('XendConfig: IP Address: %s' % dev_info['ip']) if dev_type == 'vbd': if dev_info.get('dev', '').startswith('ioemu:'): @@ -936,11 +939,18 @@ class XendConfig(dict): dev_info['uuid'] = dev_uuid # store dev references by uuid for certain device types - self['devices'][dev_uuid] = (dev_type, dev_info) + target['devices'][dev_uuid] = (dev_type, dev_info) if dev_type in ('vif', 'vbd', 'vtpm'): - self['%s_refs' % dev_type].append(dev_uuid) + param = '%s_refs' % dev_type + if param not in target: + target[param] = [] + if dev_uuid in target[param]: + target[param].append(dev_uuid) elif dev_type in ('tap',): - self['vbd_refs'].append(dev_uuid) + if 'vbd_refs' not in target: + target['vbd_refs'] = [] + if dev_uuid in target['vbd_refs']: + target['vbd_refs'].append(dev_uuid) return dev_uuid From 0be2a505dd7a4c7a544f8c561b3fb0ba5ad2ed80 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 14:57:14 +0000 Subject: [PATCH 243/282] [XEN] Add new safe pte update macros and use as necessary when updating active pagetables. Signed-off-by: Keir Fraser --- xen/arch/x86/mm.c | 54 +++++++++++++----------- xen/arch/x86/mm/shadow/multi.c | 2 + xen/arch/x86/x86_32/domain_page.c | 10 ++--- xen/arch/x86/x86_32/mm.c | 33 ++++++++------- xen/arch/x86/x86_64/mm.c | 31 +++++++------- xen/include/asm-x86/page.h | 15 +++++-- xen/include/asm-x86/x86_32/page-2level.h | 3 +- xen/include/asm-x86/x86_32/page-3level.h | 7 +++ xen/include/asm-x86/x86_64/page.h | 3 +- 9 files changed, 94 insertions(+), 64 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 48dea7cffb..9a965f982b 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -335,7 +335,7 @@ void make_cr3(struct vcpu *v, unsigned long mfn) cache->high_mfn = mfn; /* Map the guest L3 table and copy to the chosen low-memory cache. */ - *(fix_pae_highmem_pl1e - cpu) = l1e_from_pfn(mfn, __PAGE_HYPERVISOR); + l1e_write(fix_pae_highmem_pl1e-cpu, l1e_from_pfn(mfn, __PAGE_HYPERVISOR)); /* First check the previous high mapping can't be in the TLB. * (i.e. have we loaded CR3 since we last did this?) */ if ( unlikely(this_cpu(make_cr3_timestamp) == this_cpu(tlbflush_time)) ) @@ -343,7 +343,7 @@ void make_cr3(struct vcpu *v, unsigned long mfn) highmem_l3tab = (l3_pgentry_t *)fix_to_virt(FIX_PAE_HIGHMEM_0 + cpu); lowmem_l3tab = cache->table[cache->inuse_idx]; memcpy(lowmem_l3tab, highmem_l3tab, sizeof(cache->table[0])); - *(fix_pae_highmem_pl1e - cpu) = l1e_empty(); + l1e_write(fix_pae_highmem_pl1e-cpu, l1e_empty()); this_cpu(make_cr3_timestamp) = this_cpu(tlbflush_time); v->arch.cr3 = __pa(lowmem_l3tab); @@ -380,7 +380,7 @@ void invalidate_shadow_ldt(struct vcpu *v) { pfn = l1e_get_pfn(v->arch.perdomain_ptes[i]); if ( pfn == 0 ) continue; - v->arch.perdomain_ptes[i] = l1e_empty(); + l1e_write(&v->arch.perdomain_ptes[i], l1e_empty()); page = mfn_to_page(pfn); ASSERT_PAGE_IS_TYPE(page, PGT_ldt_page); ASSERT_PAGE_IS_DOMAIN(page, v->domain); @@ -449,7 +449,7 @@ int map_ldt_shadow_page(unsigned int off) nl1e = l1e_from_pfn(mfn, l1e_get_flags(l1e) | _PAGE_RW); - v->arch.perdomain_ptes[off + 16] = nl1e; + l1e_write(&v->arch.perdomain_ptes[off + 16], nl1e); v->arch.shadow_ldt_mapcnt++; return 1; @@ -851,7 +851,7 @@ static int alloc_l1_table(struct page_info *page) static int create_pae_xen_mappings(l3_pgentry_t *pl3e) { struct page_info *page; - l2_pgentry_t *pl2e; + l2_pgentry_t *pl2e, l2e; l3_pgentry_t l3e3; int i; @@ -892,15 +892,19 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e) &idle_pg_table_l2[L2_PAGETABLE_FIRST_XEN_SLOT], L2_PAGETABLE_XEN_SLOTS * sizeof(l2_pgentry_t)); for ( i = 0; i < PDPT_L2_ENTRIES; i++ ) - pl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i] = - l2e_from_page( - virt_to_page(page_get_owner(page)->arch.mm_perdomain_pt) + i, - __PAGE_HYPERVISOR); + { + l2e = l2e_from_page( + virt_to_page(page_get_owner(page)->arch.mm_perdomain_pt) + i, + __PAGE_HYPERVISOR); + l2e_write(&pl2e[l2_table_offset(PERDOMAIN_VIRT_START) + i], l2e); + } for ( i = 0; i < (LINEARPT_MBYTES >> (L2_PAGETABLE_SHIFT - 20)); i++ ) - pl2e[l2_table_offset(LINEAR_PT_VIRT_START) + i] = - (l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) ? - l2e_from_pfn(l3e_get_pfn(pl3e[i]), __PAGE_HYPERVISOR) : - l2e_empty(); + { + l2e = l2e_empty(); + if ( l3e_get_flags(pl3e[i]) & _PAGE_PRESENT ) + l2e = l2e_from_pfn(l3e_get_pfn(pl3e[i]), __PAGE_HYPERVISOR); + l2e_write(&pl2e[l2_table_offset(LINEAR_PT_VIRT_START) + i], l2e); + } unmap_domain_page(pl2e); return 1; @@ -2760,7 +2764,7 @@ void destroy_gdt(struct vcpu *v) { if ( (pfn = l1e_get_pfn(v->arch.perdomain_ptes[i])) != 0 ) put_page_and_type(mfn_to_page(pfn)); - v->arch.perdomain_ptes[i] = l1e_empty(); + l1e_write(&v->arch.perdomain_ptes[i], l1e_empty()); v->arch.guest_context.gdt_frames[i] = 0; } } @@ -2794,8 +2798,8 @@ long set_gdt(struct vcpu *v, for ( i = 0; i < nr_pages; i++ ) { v->arch.guest_context.gdt_frames[i] = frames[i]; - v->arch.perdomain_ptes[i] = - l1e_from_pfn(frames[i], __PAGE_HYPERVISOR); + l1e_write(&v->arch.perdomain_ptes[i], + l1e_from_pfn(frames[i], __PAGE_HYPERVISOR)); } return 0; @@ -3298,8 +3302,8 @@ int map_pages_to_xen( !map_small_pages ) { /* Super-page mapping. */ - ol2e = *pl2e; - *pl2e = l2e_from_pfn(mfn, flags|_PAGE_PSE); + ol2e = *pl2e; + l2e_write(pl2e, l2e_from_pfn(mfn, flags|_PAGE_PSE)); if ( (l2e_get_flags(ol2e) & _PAGE_PRESENT) ) { @@ -3319,22 +3323,24 @@ int map_pages_to_xen( { pl1e = page_to_virt(alloc_xen_pagetable()); clear_page(pl1e); - *pl2e = l2e_from_page(virt_to_page(pl1e), __PAGE_HYPERVISOR); + l2e_write(pl2e, l2e_from_page(virt_to_page(pl1e), + __PAGE_HYPERVISOR)); } else if ( l2e_get_flags(*pl2e) & _PAGE_PSE ) { pl1e = page_to_virt(alloc_xen_pagetable()); for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - pl1e[i] = l1e_from_pfn( - l2e_get_pfn(*pl2e) + i, - l2e_get_flags(*pl2e) & ~_PAGE_PSE); - *pl2e = l2e_from_page(virt_to_page(pl1e), __PAGE_HYPERVISOR); + l1e_write(&pl1e[i], + l1e_from_pfn(l2e_get_pfn(*pl2e) + i, + l2e_get_flags(*pl2e) & ~_PAGE_PSE)); + l2e_write(pl2e, l2e_from_page(virt_to_page(pl1e), + __PAGE_HYPERVISOR)); local_flush_tlb_pge(); } pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(virt); ol1e = *pl1e; - *pl1e = l1e_from_pfn(mfn, flags); + l1e_write(pl1e, l1e_from_pfn(mfn, flags)); if ( (l1e_get_flags(ol1e) & _PAGE_PRESENT) ) local_flush_tlb_one(virt); diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 98ff07ace4..211b98b2ed 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -851,7 +851,9 @@ static inline void safe_write_entry(void *dst, void *src) * then writing the high word before the low word. */ BUILD_BUG_ON(sizeof (shadow_l1e_t) != 2 * sizeof (unsigned long)); d[0] = 0; + wmb(); d[1] = s[1]; + wmb(); d[0] = s[0]; #else /* In 32-bit and 64-bit, sizeof(pte) == sizeof(ulong) == 1 word, diff --git a/xen/arch/x86/x86_32/domain_page.c b/xen/arch/x86/x86_32/domain_page.c index 93cd2379a7..9080de1a87 100644 --- a/xen/arch/x86/x86_32/domain_page.c +++ b/xen/arch/x86/x86_32/domain_page.c @@ -107,7 +107,7 @@ void *map_domain_page(unsigned long mfn) spin_unlock(&cache->lock); - cache->l1tab[idx] = l1e_from_pfn(mfn, __PAGE_HYPERVISOR); + l1e_write(&cache->l1tab[idx], l1e_from_pfn(mfn, __PAGE_HYPERVISOR)); out: va = MAPCACHE_VIRT_START + (idx << PAGE_SHIFT); @@ -147,7 +147,7 @@ void unmap_domain_page(void *va) { /* /First/, zap the PTE. */ ASSERT(l1e_get_pfn(cache->l1tab[hashent->idx]) == hashent->mfn); - cache->l1tab[hashent->idx] = l1e_empty(); + l1e_write(&cache->l1tab[hashent->idx], l1e_empty()); /* /Second/, mark as garbage. */ set_bit(hashent->idx, cache->garbage); } @@ -159,7 +159,7 @@ void unmap_domain_page(void *va) else { /* /First/, zap the PTE. */ - cache->l1tab[idx] = l1e_empty(); + l1e_write(&cache->l1tab[idx], l1e_empty()); /* /Second/, mark as garbage. */ set_bit(idx, cache->garbage); } @@ -229,7 +229,7 @@ void *map_domain_page_global(unsigned long mfn) pl2e = virt_to_xen_l2e(va); pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(va); - *pl1e = l1e_from_pfn(mfn, __PAGE_HYPERVISOR); + l1e_write(pl1e, l1e_from_pfn(mfn, __PAGE_HYPERVISOR)); return (void *)va; } @@ -246,7 +246,7 @@ void unmap_domain_page_global(void *va) /* /First/, we zap the PTE. */ pl2e = virt_to_xen_l2e(__va); pl1e = l2e_to_l1e(*pl2e) + l1_table_offset(__va); - *pl1e = l1e_empty(); + l1e_write(pl1e, l1e_empty()); /* /Second/, we add to the garbage map. */ idx = (__va - IOREMAP_VIRT_START) >> PAGE_SHIFT; diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index 116228a53d..4978b82dad 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -99,11 +99,12 @@ void __init paging_init(void) { if ( (pg = alloc_domheap_pages(NULL, PAGETABLE_ORDER, 0)) == NULL ) panic("Not enough memory to bootstrap Xen.\n"); - idle_pg_table_l2[l2_linear_offset(RDWR_MPT_VIRT_START) + i] = - l2e_from_page(pg, PAGE_HYPERVISOR | _PAGE_PSE); + l2e_write(&idle_pg_table_l2[l2_linear_offset(RDWR_MPT_VIRT_START) + i], + l2e_from_page(pg, PAGE_HYPERVISOR | _PAGE_PSE)); /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */ - idle_pg_table_l2[l2_linear_offset(RO_MPT_VIRT_START) + i] = - l2e_from_page(pg, (__PAGE_HYPERVISOR | _PAGE_PSE) & ~_PAGE_RW); + l2e_write(&idle_pg_table_l2[l2_linear_offset(RO_MPT_VIRT_START) + i], + l2e_from_page( + pg, (__PAGE_HYPERVISOR | _PAGE_PSE) & ~_PAGE_RW)); } /* Fill with an obvious debug pattern. */ @@ -115,8 +116,8 @@ void __init paging_init(void) { ioremap_pt = alloc_xenheap_page(); clear_page(ioremap_pt); - idle_pg_table_l2[l2_linear_offset(IOREMAP_VIRT_START) + i] = - l2e_from_page(virt_to_page(ioremap_pt), __PAGE_HYPERVISOR); + l2e_write(&idle_pg_table_l2[l2_linear_offset(IOREMAP_VIRT_START) + i], + l2e_from_page(virt_to_page(ioremap_pt), __PAGE_HYPERVISOR)); } } @@ -125,10 +126,10 @@ void __init setup_idle_pagetable(void) int i; for ( i = 0; i < PDPT_L2_ENTRIES; i++ ) - idle_pg_table_l2[l2_linear_offset(PERDOMAIN_VIRT_START) + i] = - l2e_from_page(virt_to_page(idle_vcpu[0]->domain-> - arch.mm_perdomain_pt) + i, - __PAGE_HYPERVISOR); + l2e_write(&idle_pg_table_l2[l2_linear_offset(PERDOMAIN_VIRT_START)+i], + l2e_from_page(virt_to_page(idle_vcpu[0]->domain-> + arch.mm_perdomain_pt) + i, + __PAGE_HYPERVISOR)); } void __init zap_low_mappings(l2_pgentry_t *base) @@ -136,14 +137,16 @@ void __init zap_low_mappings(l2_pgentry_t *base) int i; u32 addr; - for (i = 0; ; i++) { - addr = (i << L2_PAGETABLE_SHIFT); - if (addr >= HYPERVISOR_VIRT_START) + for ( i = 0; ; i++ ) + { + addr = i << L2_PAGETABLE_SHIFT; + if ( addr >= HYPERVISOR_VIRT_START ) break; - if (l2e_get_paddr(base[i]) != addr) + if ( l2e_get_paddr(base[i]) != addr ) continue; - base[i] = l2e_empty(); + l2e_write(&base[i], l2e_empty()); } + flush_tlb_all_pge(); } diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index c2783e897d..e14d266e12 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -59,7 +59,7 @@ l2_pgentry_t *virt_to_xen_l2e(unsigned long v) { pl3e = page_to_virt(alloc_xen_pagetable()); clear_page(pl3e); - *pl4e = l4e_from_paddr(__pa(pl3e), __PAGE_HYPERVISOR); + l4e_write(pl4e, l4e_from_paddr(__pa(pl3e), __PAGE_HYPERVISOR)); } pl3e = l4e_to_l3e(*pl4e) + l3_table_offset(v); @@ -67,7 +67,7 @@ l2_pgentry_t *virt_to_xen_l2e(unsigned long v) { pl2e = page_to_virt(alloc_xen_pagetable()); clear_page(pl2e); - *pl3e = l3e_from_paddr(__pa(pl2e), __PAGE_HYPERVISOR); + l3e_write(pl3e, l3e_from_paddr(__pa(pl2e), __PAGE_HYPERVISOR)); } pl2e = l3e_to_l2e(*pl3e) + l2_table_offset(v); @@ -85,8 +85,8 @@ void __init paging_init(void) if ( (l2_pg = alloc_domheap_page(NULL)) == NULL ) goto nomem; l3_ro_mpt = clear_page(page_to_virt(l2_pg)); - idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)] = - l4e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER); + l4e_write(&idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)], + l4e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER)); /* * Allocate and map the machine-to-phys table. @@ -111,18 +111,19 @@ void __init paging_init(void) goto nomem; va = RO_MPT_VIRT_START + (i << L2_PAGETABLE_SHIFT); l2_ro_mpt = clear_page(page_to_virt(l2_pg)); - l3_ro_mpt[l3_table_offset(va)] = - l3e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER); + l3e_write(&l3_ro_mpt[l3_table_offset(va)], + l3e_from_page(l2_pg, __PAGE_HYPERVISOR | _PAGE_USER)); l2_ro_mpt += l2_table_offset(va); } /* NB. Cannot be GLOBAL as shadow_mode_translate reuses this area. */ - *l2_ro_mpt++ = l2e_from_page( - l1_pg, /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT); + l2e_write(l2_ro_mpt, l2e_from_page( + l1_pg, /*_PAGE_GLOBAL|*/_PAGE_PSE|_PAGE_USER|_PAGE_PRESENT)); + l2_ro_mpt++; } /* Set up linear page table mapping. */ - idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)] = - l4e_from_paddr(__pa(idle_pg_table), __PAGE_HYPERVISOR); + l4e_write(&idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)], + l4e_from_paddr(__pa(idle_pg_table), __PAGE_HYPERVISOR)); return; nomem: @@ -132,15 +133,15 @@ void __init paging_init(void) void __init setup_idle_pagetable(void) { /* Install per-domain mappings for idle domain. */ - idle_pg_table[l4_table_offset(PERDOMAIN_VIRT_START)] = - l4e_from_page( - virt_to_page(idle_vcpu[0]->domain->arch.mm_perdomain_l3), - __PAGE_HYPERVISOR); + l4e_write(&idle_pg_table[l4_table_offset(PERDOMAIN_VIRT_START)], + l4e_from_page( + virt_to_page(idle_vcpu[0]->domain->arch.mm_perdomain_l3), + __PAGE_HYPERVISOR)); } void __init zap_low_mappings(void) { - idle_pg_table[0] = l4e_empty(); + l4e_write(&idle_pg_table[0], l4e_empty()); flush_tlb_all_pge(); } diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index b9c921a5cd..d384d34d65 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -33,9 +33,18 @@ /* Write a pte atomically to memory. */ #define l1e_write_atomic(l1ep, l1e) pte_write_atomic(l1ep, l1e_get_intpte(l1e)) -#define l2e_write_atomic(l2ep, l2e) pte_write_atomic(l2ep, l1e_get_intpte(l2e)) -#define l3e_write_atomic(l3ep, l3e) pte_write_atomic(l3ep, l1e_get_intpte(l3e)) -#define l4e_write_atomic(l4ep, l4e) pte_write_atomic(l4ep, l1e_get_intpte(l4e)) +#define l2e_write_atomic(l2ep, l2e) pte_write_atomic(l2ep, l2e_get_intpte(l2e)) +#define l3e_write_atomic(l3ep, l3e) pte_write_atomic(l3ep, l3e_get_intpte(l3e)) +#define l4e_write_atomic(l4ep, l4e) pte_write_atomic(l4ep, l4e_get_intpte(l4e)) + +/* + * Write a pte safely but non-atomically to memory. + * The PTE may become temporarily not-present during the update. + */ +#define l1e_write(l1ep, l1e) pte_write(l1ep, l1e_get_intpte(l1e)) +#define l2e_write(l2ep, l2e) pte_write(l2ep, l2e_get_intpte(l2e)) +#define l3e_write(l3ep, l3e) pte_write(l3ep, l3e_get_intpte(l3e)) +#define l4e_write(l4ep, l4e) pte_write(l4ep, l4e_get_intpte(l4e)) /* Get direct integer representation of a pte's contents (intpte_t). */ #define l1e_get_intpte(x) ((x).l1) diff --git a/xen/include/asm-x86/x86_32/page-2level.h b/xen/include/asm-x86/x86_32/page-2level.h index a022b12087..86e8dbe30f 100644 --- a/xen/include/asm-x86/x86_32/page-2level.h +++ b/xen/include/asm-x86/x86_32/page-2level.h @@ -29,7 +29,8 @@ typedef l2_pgentry_t root_pgentry_t; #endif /* !__ASSEMBLY__ */ #define pte_read_atomic(ptep) (*(intpte_t *)(ptep)) -#define pte_write_atomic(ptep, pte) (*(intpte_t *)(ptep)) = (pte)) +#define pte_write_atomic(ptep, pte) ((*(intpte_t *)(ptep)) = (pte)) +#define pte_write(ptep, pte) ((*(intpte_t *)(ptep)) = (pte)) /* root table */ #define root_get_pfn l2e_get_pfn diff --git a/xen/include/asm-x86/x86_32/page-3level.h b/xen/include/asm-x86/x86_32/page-3level.h index 08864255ad..41bc5b0cff 100644 --- a/xen/include/asm-x86/x86_32/page-3level.h +++ b/xen/include/asm-x86/x86_32/page-3level.h @@ -48,6 +48,13 @@ typedef l3_pgentry_t root_pgentry_t; while ( (__npte = cmpxchg((intpte_t *)(ptep), __pte, (pte))) != __pte ) \ __pte = __npte; \ } while ( 0 ) +#define pte_write(ptep, pte) do { \ + *((u32 *)(ptep)+0) = 0; \ + wmb(); \ + *((u32 *)(ptep)+1) = (pte) >> 32; \ + wmb(); \ + *((u32 *)(ptep)+0) = (pte) >> 0; \ +} while ( 0 ) /* root table */ #define root_get_pfn l3e_get_pfn diff --git a/xen/include/asm-x86/x86_64/page.h b/xen/include/asm-x86/x86_64/page.h index e52097d73e..fca1173c1e 100644 --- a/xen/include/asm-x86/x86_64/page.h +++ b/xen/include/asm-x86/x86_64/page.h @@ -44,7 +44,8 @@ typedef l4_pgentry_t root_pgentry_t; #endif /* !__ASSEMBLY__ */ #define pte_read_atomic(ptep) (*(intpte_t *)(ptep)) -#define pte_write_atomic(ptep, pte) (*(intpte_t *)(ptep)) = (pte)) +#define pte_write_atomic(ptep, pte) ((*(intpte_t *)(ptep)) = (pte)) +#define pte_write(ptep, pte) ((*(intpte_t *)(ptep)) = (pte)) /* Given a virtual address, get an entry offset into a linear page table. */ #define l1_linear_offset(_a) (((_a) & VADDR_MASK) >> L1_PAGETABLE_SHIFT) From 69370cc992643992941d7d65d591f26cc2bf0cc3 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 16:08:44 +0000 Subject: [PATCH 244/282] [XEND] Sync Xen API with newer VDB and VIF specification. Fix breakage with storing VIF and VBD refs, remove extraneous debugging. Also fixing some type errors in default values for Xen API if things are missing in XendConfig. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendAPI.py | 11 +++--- tools/python/xen/xend/XendConfig.py | 5 ++- tools/python/xen/xend/XendDomainInfo.py | 46 +++++++------------------ 3 files changed, 19 insertions(+), 43 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index 0b4e35b8ce..f59153e68b 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -1036,8 +1036,8 @@ class XendAPI: # regular xm created VBDs VBD_attr_ro = ['image', - 'IO_bandwidth_incoming_kbs', - 'IO_bandwidth_outgoing_kbs'] + 'io_read_kbs', + 'io_write_kbs'] VBD_attr_rw = ['VM', 'VDI', 'device', @@ -1113,10 +1113,8 @@ class XendAPI: # Xen API: Class VIF # ---------------------------------------------------------------- - VIF_attr_ro = ['network_read_kbs', - 'network_write_kbs', - 'IO_bandwidth_incoming_kbs', - 'IO_bandwidth_outgoing_kbs'] + VIF_attr_ro = ['io_read_kbs', + 'io_write_kbs'] VIF_attr_rw = ['name', 'type', 'device', @@ -1138,6 +1136,7 @@ class XendAPI: return xen_api_error(XEND_ERROR_VIF_INVALID) valid_vif_keys = self.VIF_attr_ro + self.VIF_attr_rw + \ self.Base_attr_ro + self.Base_attr_rw + for k in cfg.keys(): if k not in valid_vif_keys: del cfg[k] diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 526e8836a5..74ff06284d 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -925,7 +925,6 @@ class XendConfig(dict): if dev_type == 'vif' and 'ip' in dev_info: dev_info['ip'] = _get_config_ipaddr(config) - log.debug('XendConfig: IP Address: %s' % dev_info['ip']) if dev_type == 'vbd': if dev_info.get('dev', '').startswith('ioemu:'): @@ -944,12 +943,12 @@ class XendConfig(dict): param = '%s_refs' % dev_type if param not in target: target[param] = [] - if dev_uuid in target[param]: + if dev_uuid not in target[param]: target[param].append(dev_uuid) elif dev_type in ('tap',): if 'vbd_refs' not in target: target['vbd_refs'] = [] - if dev_uuid in target['vbd_refs']: + if dev_uuid not in target['vbd_refs']: target['vbd_refs'].append(dev_uuid) return dev_uuid diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index a86518ab40..3716be8462 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1780,13 +1780,13 @@ class XendDomainInfo: return dom_uuid def get_memory_static_max(self): - return self.info.get('memory_static_max') + return self.info.get('memory_static_max', 0) def get_memory_static_min(self): - return self.info.get('memory_static_min') + return self.info.get('memory_static_min', 0) def get_memory_dynamic_max(self): - return self.info.get('memory_dynamic_min') + return self.info.get('memory_dynamic_min', 0) def get_memory_dynamic_min(self): - return self.info.get('memory_dynamic_max') + return self.info.get('memory_dynamic_max', 0) def get_vcpus_policy(self): @@ -1820,7 +1820,7 @@ class XendDomainInfo: def get_builder(self): return self.info.get('builder', 0) def get_boot_method(self): - return self.info.get('boot_method', '') + return self.info.get('boot_method', XEN_API_BOOT_TYPE[2]) def get_kernel_image(self): return self.info.get('kernel_kernel', '') def get_kernel_initrd(self): @@ -1830,7 +1830,7 @@ class XendDomainInfo: def get_grub_cmdline(self): return '' # TODO def get_pci_bus(self): - return 0 # TODO + return '' # TODO def get_tools_version(self): return {} # TODO def get_other_config(self): @@ -1925,18 +1925,16 @@ class XendDomainInfo: config['network'] = '' # Invalid for Xend config['MTU'] = 1500 # TODO - config['network_read_kbs'] = 0.0 - config['network_write_kbs'] = 0.0 - config['IO_bandwidth_incoming_kbs'] = 0.0 - config['IO_bandwidth_outgoing_kbs'] = 0.0 + config['io_read_kbs'] = 0.0 + config['io_write_kbs'] = 0.0 if dev_class == 'vbd': - config['VDI'] = '' # TODO + config['VDI'] = config.get('VDI', '') config['device'] = config.get('dev', '') config['driver'] = 'paravirtualised' # TODO config['image'] = config.get('uname', '') - config['IO_bandwidth_incoming_kbs'] = 0.0 - config['IO_bandwidth_outgoing_kbs'] = 0.0 + config['io_read_kbs'] = 0.0 + config['io_write_kbs'] = 0.0 if config['mode'] == 'r': config['mode'] = 'RO' else: @@ -2050,27 +2048,7 @@ class XendDomainInfo: return dev_uuid def has_device(self, dev_class, dev_uuid): - return (dev_uuid in self.info['%s_refs' % dev_class]) - - """ - def stateChar(name): - if name in self.info: - if self.info[name]: - return name[0] - else: - return '-' - else: - return '?' - - state = reduce(lambda x, y: x + y, map(stateChar, DOM_STATES_OLD)) - - sxpr.append(['state', state]) - - if self.store_mfn: - sxpr.append(['store_mfn', self.store_mfn]) - if self.console_mfn: - sxpr.append(['console_mfn', self.console_mfn]) - """ + return (dev_uuid in self.info['%s_refs' % dev_class.lower()]) def __str__(self): return '' % \ From a8b5e33ac829c0adb072c2acd67993fc1a77be39 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Thu, 7 Dec 2006 16:43:08 +0000 Subject: [PATCH 245/282] [LINUX] Fail gracefully if we run out of spare IRQs. Signed-off-by: Keir Fraser --- .../arch/i386/kernel/time-xen.c | 24 ++++--- .../drivers/xen/core/evtchn.c | 38 ++++++++--- .../drivers/xen/core/smpboot.c | 68 ++++++++++++------- .../drivers/xen/netback/netback.c | 13 ++-- 4 files changed, 93 insertions(+), 50 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c index 93388ea67a..816b890050 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c @@ -1047,9 +1047,9 @@ void time_resume(void) #ifdef CONFIG_SMP static char timer_name[NR_CPUS][15]; -void local_setup_timer(unsigned int cpu) +int local_setup_timer(unsigned int cpu) { - int seq; + int seq, irq; BUG_ON(cpu == 0); @@ -1062,15 +1062,17 @@ void local_setup_timer(unsigned int cpu) } while (read_seqretry(&xtime_lock, seq)); sprintf(timer_name[cpu], "timer%d", cpu); - per_cpu(timer_irq, cpu) = - bind_virq_to_irqhandler( - VIRQ_TIMER, - cpu, - timer_interrupt, - SA_INTERRUPT, - timer_name[cpu], - NULL); - BUG_ON(per_cpu(timer_irq, cpu) < 0); + irq = bind_virq_to_irqhandler(VIRQ_TIMER, + cpu, + timer_interrupt, + SA_INTERRUPT, + timer_name[cpu], + NULL); + if (irq < 0) + return irq; + per_cpu(timer_irq, cpu) = irq; + + return 0; } void local_teardown_timer(unsigned int cpu) diff --git a/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c b/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c index b455a3b10a..d596da3888 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c @@ -251,8 +251,15 @@ static int find_unbound_irq(void) if (irq_bindcount[irq] == 0) break; - if (irq == NR_IRQS) - panic("No available IRQ to bind to: increase NR_IRQS!\n"); + if (irq == NR_IRQS) { + static int warned; + if (!warned) { + warned = 1; + printk(KERN_WARNING "No available IRQ to bind to: " + "increase NR_IRQS!\n"); + } + return -ENOSPC; + } return irq; } @@ -264,15 +271,17 @@ static int bind_evtchn_to_irq(unsigned int evtchn) spin_lock(&irq_mapping_update_lock); if ((irq = evtchn_to_irq[evtchn]) == -1) { - irq = find_unbound_irq(); + if ((irq = find_unbound_irq()) < 0) + goto out; + evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_EVTCHN, 0, evtchn); } irq_bindcount[irq]++; + out: spin_unlock(&irq_mapping_update_lock); - return irq; } @@ -284,6 +293,9 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) spin_lock(&irq_mapping_update_lock); if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) { + if ((irq = find_unbound_irq()) < 0) + goto out; + bind_virq.virq = virq; bind_virq.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, @@ -291,7 +303,6 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) BUG(); evtchn = bind_virq.port; - irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn); @@ -302,8 +313,8 @@ static int bind_virq_to_irq(unsigned int virq, unsigned int cpu) irq_bindcount[irq]++; + out: spin_unlock(&irq_mapping_update_lock); - return irq; } @@ -315,13 +326,15 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) spin_lock(&irq_mapping_update_lock); if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) { + if ((irq = find_unbound_irq()) < 0) + goto out; + bind_ipi.vcpu = cpu; if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi, &bind_ipi) != 0) BUG(); evtchn = bind_ipi.port; - irq = find_unbound_irq(); evtchn_to_irq[evtchn] = irq; irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn); @@ -332,8 +345,8 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu) irq_bindcount[irq]++; + out: spin_unlock(&irq_mapping_update_lock); - return irq; } @@ -383,6 +396,9 @@ int bind_evtchn_to_irqhandler( int retval; irq = bind_evtchn_to_irq(evtchn); + if (irq < 0) + return irq; + retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { unbind_from_irq(irq); @@ -405,6 +421,9 @@ int bind_virq_to_irqhandler( int retval; irq = bind_virq_to_irq(virq, cpu); + if (irq < 0) + return irq; + retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { unbind_from_irq(irq); @@ -427,6 +446,9 @@ int bind_ipi_to_irqhandler( int retval; irq = bind_ipi_to_irq(ipi, cpu); + if (irq < 0) + return irq; + retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { unbind_from_irq(irq); diff --git a/linux-2.6-xen-sparse/drivers/xen/core/smpboot.c b/linux-2.6-xen-sparse/drivers/xen/core/smpboot.c index 2538791d0e..36d5a884d4 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/smpboot.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/smpboot.c @@ -33,7 +33,7 @@ extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *); extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *); -extern void local_setup_timer(unsigned int cpu); +extern int local_setup_timer(unsigned int cpu); extern void local_teardown_timer(unsigned int cpu); extern void hypervisor_callback(void); @@ -110,32 +110,45 @@ set_cpu_sibling_map(int cpu) cpu_data[cpu].booted_cores = 1; } -static void xen_smp_intr_init(unsigned int cpu) +static int xen_smp_intr_init(unsigned int cpu) { + int rc; + + per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1; + sprintf(resched_name[cpu], "resched%d", cpu); - per_cpu(resched_irq, cpu) = - bind_ipi_to_irqhandler( - RESCHEDULE_VECTOR, - cpu, - smp_reschedule_interrupt, - SA_INTERRUPT, - resched_name[cpu], - NULL); - BUG_ON(per_cpu(resched_irq, cpu) < 0); + rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR, + cpu, + smp_reschedule_interrupt, + SA_INTERRUPT, + resched_name[cpu], + NULL); + if (rc < 0) + goto fail; + per_cpu(resched_irq, cpu) = rc; sprintf(callfunc_name[cpu], "callfunc%d", cpu); - per_cpu(callfunc_irq, cpu) = - bind_ipi_to_irqhandler( - CALL_FUNCTION_VECTOR, - cpu, - smp_call_function_interrupt, - SA_INTERRUPT, - callfunc_name[cpu], - NULL); - BUG_ON(per_cpu(callfunc_irq, cpu) < 0); + rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR, + cpu, + smp_call_function_interrupt, + SA_INTERRUPT, + callfunc_name[cpu], + NULL); + if (rc < 0) + goto fail; + per_cpu(callfunc_irq, cpu) = rc; - if (cpu != 0) - local_setup_timer(cpu); + if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0)) + goto fail; + + return 0; + + fail: + if (per_cpu(resched_irq, cpu) >= 0) + unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL); + if (per_cpu(callfunc_irq, cpu) >= 0) + unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL); + return rc; } #ifdef CONFIG_HOTPLUG_CPU @@ -253,7 +266,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus) set_cpu_sibling_map(0); - xen_smp_intr_init(0); + if (xen_smp_intr_init(0)) + BUG(); /* Restrict the possible_map according to max_cpus. */ while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) { @@ -419,7 +433,13 @@ int __devinit __cpu_up(unsigned int cpu) set_cpu_sibling_map(cpu); wmb(); - xen_smp_intr_init(cpu); + + rc = xen_smp_intr_init(cpu); + if (rc) { + remove_siblinginfo(cpu); + return rc; + } + cpu_set(cpu, cpu_online_map); rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL); diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index 1d24fc9b88..f05802aa2e 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -1506,13 +1506,12 @@ static int __init netback_init(void) netif_xenbus_init(); #ifdef NETBE_DEBUG_INTERRUPT - (void)bind_virq_to_irqhandler( - VIRQ_DEBUG, - 0, - netif_be_dbg, - SA_SHIRQ, - "net-be-dbg", - &netif_be_dbg); + (void)bind_virq_to_irqhandler(VIRQ_DEBUG, + 0, + netif_be_dbg, + SA_SHIRQ, + "net-be-dbg", + &netif_be_dbg); #endif return 0; From eee69a2a82227a8491c69fd3b11c77bf2f543e90 Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Thu, 7 Dec 2006 16:43:22 +0000 Subject: [PATCH 246/282] [XEND] Only return valid VIF and VBD parameters via Xen API. Also fix typo for memory_dynamic_{min,max}. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendAPI.py | 19 +++++++++++++++---- tools/python/xen/xend/XendDomainInfo.py | 4 ++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/tools/python/xen/xend/XendAPI.py b/tools/python/xen/xend/XendAPI.py index f59153e68b..e2640589ec 100644 --- a/tools/python/xen/xend/XendAPI.py +++ b/tools/python/xen/xend/XendAPI.py @@ -1057,7 +1057,16 @@ class XendAPI: cfg = vm.get_dev_xenapi_config('vbd', vbd_ref) if not cfg: return xen_api_error(XEND_ERROR_VBD_INVALID) - return xen_api_success(cfg) + + valid_vbd_keys = self.VBD_attr_ro + self.VBD_attr_rw + \ + self.Base_attr_ro + self.Base_attr_rw + + return_cfg = {} + for k in cfg.keys(): + if k in valid_vbd_keys: + return_cfg[k] = cfg[k] + + return xen_api_success(return_cfg) def VBD_media_change(self, session, vbd_ref, vdi_ref): return xen_api_error(XEND_ERROR_UNSUPPORTED) @@ -1134,14 +1143,16 @@ class XendAPI: cfg = vm.get_dev_xenapi_config('vif', vif_ref) if not cfg: return xen_api_error(XEND_ERROR_VIF_INVALID) + valid_vif_keys = self.VIF_attr_ro + self.VIF_attr_rw + \ self.Base_attr_ro + self.Base_attr_rw + return_cfg = {} for k in cfg.keys(): - if k not in valid_vif_keys: - del cfg[k] + if k in valid_vif_keys: + return_cfg[k] = cfg[k] - return xen_api_success(cfg) + return xen_api_success(return_cfg) # class methods def VIF_create(self, session, vif_struct): diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 3716be8462..29ce17083c 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -1784,9 +1784,9 @@ class XendDomainInfo: def get_memory_static_min(self): return self.info.get('memory_static_min', 0) def get_memory_dynamic_max(self): - return self.info.get('memory_dynamic_min', 0) - def get_memory_dynamic_min(self): return self.info.get('memory_dynamic_max', 0) + def get_memory_dynamic_min(self): + return self.info.get('memory_dynamic_min', 0) def get_vcpus_policy(self): From 4f2a113ba67dbdae178b2beb12a39dbaf0e70ff6 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 17:47:43 +0000 Subject: [PATCH 247/282] Diagnose bad config files. Signed-off-by: Ewan Mellor --- tools/python/xen/xm/main.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 9151848d30..6850061908 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -335,17 +335,22 @@ all_commands = (domain_commands + host_commands + scheduler_commands + # Configuration File Parsing ## +config = None if os.path.isfile(XM_CONFIG_FILE): - config = xml.dom.minidom.parse(XM_CONFIG_FILE) -else: - config = None + try: + config = xml.dom.minidom.parse(XM_CONFIG_FILE) + except: + print >>sys.stderr, ('Ignoring invalid configuration file %s.' % + XM_CONFIG_FILE) def parseServer(): if config: server = config.getElementsByTagName('server') if server: st = server[0].getAttribute('type') - if st != SERVER_XEN_API: + if st != SERVER_XEN_API and st != SERVER_LEGACY_XMLRPC: + print >>sys.stderr, ('Invalid server type %s; using %s.' % + (st, SERVER_LEGACY_XMLRPC)) st = SERVER_LEGACY_XMLRPC return (st, server[0].getAttribute('uri')) From ff3ba258ad75c5bcf4ffb837c05104314c586c7d Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Thu, 7 Dec 2006 17:48:35 +0000 Subject: [PATCH 248/282] Fix PERROR. Signed-off-by: Ewan Mellor --- tools/libxc/xc_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h index 2ddec3f988..f087e7de69 100644 --- a/tools/libxc/xc_private.h +++ b/tools/libxc/xc_private.h @@ -63,7 +63,7 @@ void xc_set_error(int code, const char *fmt, ...); #define ERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m , ## _a ) #define PERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m " (%d = %s)", \ - _m , ## _a , errno, strerror(errno)) + ## _a , errno, strerror(errno)) int lock_pages(void *addr, size_t len); void unlock_pages(void *addr, size_t len); From aa464f07de73523b957eeb056940bd2b4d50118a Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 16:18:55 -0700 Subject: [PATCH 249/282] [IA64] workaround NaT consumption fault when hiding a PCI function from dom0 The free_irq() path seems to have trouble with devices hidden from dom0 for driver domains. The result is a NaT consumption fault in the reboot notifier_call_chain() when dom0 reboots. This workaround prevents the problem until it can be further investigated. Signed-off-by: Alex Williamson --- xen/arch/ia64/xen/hypercall.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index 15e9f5b26b..69be18efcd 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -472,7 +472,12 @@ static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) vector > IA64_LAST_DEVICE_VECTOR) break; - free_irq_vector(vector); + /* XXX This should be called, but causes a NAT consumption via the + * reboot notifier_call_chain in dom0 if a device is hidden for + * a driver domain using pciback.hide= (specifically, hiding function + * 1 of a 2 port e1000 card). + * free_irq_vector(vector); + */ ret = 0; break; } From 2f96a266fedb98f33a096b4b71fbcfc26b602448 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 14:49:00 -0700 Subject: [PATCH 250/282] [IA64] Map shared_info into guest pseudo physical address space Allows libxc to map from dom0. This is used by domain builder. Signed-off-by: Isaku Yamahata --- tools/libxc/xc_linux_build.c | 20 ++++++++++++-------- xen/arch/ia64/xen/dom0_ops.c | 22 +++++++++++----------- xen/include/asm-ia64/grant_table.h | 10 +++++++++- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 104a90d991..8ddb1ed525 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -481,9 +481,7 @@ static int setup_guest(int xc_handle, start_info_t *start_info; unsigned long start_info_mpa; struct xen_ia64_boot_param *bp; -#if 0 // see comment below shared_info_t *shared_info; -#endif int i; DECLARE_DOMCTL; int rc; @@ -595,13 +593,20 @@ static int setup_guest(int xc_handle, ctxt->user_regs.r28 = start_info_mpa + sizeof (start_info_t); munmap(start_info, PAGE_SIZE); -#if 0 /* - * XXX FIXME: - * The follwoing initialization is done by XEN_DOMCTL_arch_setup as - * work around. - * Should XENMEM_add_to_physmap with XENMAPSPACE_shared_info be used? + * shared_info is assiged into guest pseudo physical address space + * by XEN_DOMCTL_arch_setup. shared_info_frame is stale value until that. + * So passed shared_info_frame is stale. obtain the right value here. */ + domctl.cmd = XEN_DOMCTL_getdomaininfo; + domctl.domain = (domid_t)dom; + if ( (xc_domctl(xc_handle, &domctl) < 0) || + ((uint16_t)domctl.domain != dom) ) + { + PERROR("Could not get info on domain"); + goto error_out; + } + shared_info_frame = domctl.u.getdomaininfo.shared_info_frame; /* shared_info page starts its life empty. */ shared_info = xc_map_foreign_range( @@ -615,7 +620,6 @@ static int setup_guest(int xc_handle, shared_info->arch.start_info_pfn = nr_pages - 3; munmap(shared_info, PAGE_SIZE); -#endif free(page_array); return 0; diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index 18c2e2f88e..472f03dc54 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -125,19 +125,19 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) for_each_vcpu (d, v) v->arch.breakimm = d->arch.breakimm; } -#if 1 - /* - * XXX FIXME - * see comment around shared_info in setup_guest() in - * libxc/xc_linux_build.c - */ { - int i; - d->shared_info->arch.start_info_pfn = ds->maxmem >> PAGE_SHIFT; - for_each_cpu(i) - d->shared_info->vcpu_info[i].evtchn_upcall_mask = 1; + /* + * XXX IA64_SHARED_INFO_PADDR + * assign these pages into guest psudo physical address + * space for dom0 to map this page by gmfn. + * this is necessary for domain build, save, restore and + * dump-core. + */ + unsigned long i; + for (i = 0; i < XSI_SIZE; i += PAGE_SIZE) + assign_domain_page(d, IA64_SHARED_INFO_PADDR + i, + virt_to_maddr(d->shared_info + i)); } -#endif } } diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h index 1d0bded64f..895d1ee936 100644 --- a/xen/include/asm-ia64/grant_table.h +++ b/xen/include/asm-ia64/grant_table.h @@ -23,8 +23,16 @@ void guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long } while (0) +/* XXX + * somewhere appropriate + * those constand shouldn't be pre-defined and + * those area should be reserved by EFI MD. + */ +/* Guest phsyical address of shared_info */ +#define IA64_SHARED_INFO_PADDR (1UL << 40) + /* Guest physical address of the grant table. */ -#define IA64_GRANT_TABLE_PADDR (1UL << 40) +#define IA64_GRANT_TABLE_PADDR (IA64_SHARED_INFO_PADDR + XSI_SIZE) #define gnttab_shared_maddr(d, t, i) \ virt_to_maddr((char*)(t)->shared + ((i) << PAGE_SHIFT)) From da1a7d7fbad42581c90a79e2194080bcab62a562 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 14:53:47 -0700 Subject: [PATCH 251/282] [IA64] Map vcpu memory mapped registers into guest psudo physical address space Assign vcpu memory mapped registers into guest psudo physical address space for foreign domain page mapping. This is used by domain save. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/domain.c | 22 +++++++++++++++++++++- xen/include/asm-ia64/grant_table.h | 7 ++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 0be27db053..8406c12708 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -308,6 +308,16 @@ void relinquish_vcpu_resources(struct vcpu *v) if (HAS_PERVCPU_VHPT(v->domain)) pervcpu_vhpt_free(v); if (v->arch.privregs != NULL) { + // this might be called by arch_do_domctl() with XEN_DOMCTL_arch_setup() + // for domVTi. + if (!(atomic_read(&v->domain->refcnt) & DOMAIN_DESTROYED)) { + unsigned long i; + for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE) + guest_physmap_remove_page(v->domain, + IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i, + virt_to_maddr(v->arch.privregs + i)); + } + free_xenheap_pages(v->arch.privregs, get_order_from_shift(XMAPPEDREGS_SHIFT)); v->arch.privregs = NULL; @@ -367,6 +377,15 @@ int vcpu_initialise(struct vcpu *v) for (i = 0; i < (1 << order); i++) share_xen_page_with_guest(virt_to_page(v->arch.privregs) + i, d, XENSHARE_writable); + /* + * XXX IA64_XMAPPEDREGS_PADDR + * assign these pages into guest pseudo physical address + * space for dom0 to map this page by gmfn. + * this is necessary for domain save, restore and dump-core. + */ + for (i = 0; i < XMAPPEDREGS_SIZE; i += PAGE_SIZE) + assign_domain_page(d, IA64_XMAPPEDREGS_PADDR(v->vcpu_id) + i, + virt_to_maddr(v->arch.privregs + i)); tlbflush_update_time(&v->arch.tlbflush_timestamp, tlbflush_current_time()); @@ -509,7 +528,8 @@ void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) struct vcpu_extra_regs *er = &c->extra_regs; c->user_regs = *vcpu_regs (v); - c->privregs_pfn = virt_to_maddr(v->arch.privregs) >> PAGE_SHIFT; + c->privregs_pfn = get_gpfn_from_mfn(virt_to_maddr(v->arch.privregs) >> + PAGE_SHIFT); /* Fill extra regs. */ for (i = 0; i < 8; i++) { diff --git a/xen/include/asm-ia64/grant_table.h b/xen/include/asm-ia64/grant_table.h index 895d1ee936..6b62d6abd3 100644 --- a/xen/include/asm-ia64/grant_table.h +++ b/xen/include/asm-ia64/grant_table.h @@ -30,9 +30,14 @@ void guest_physmap_add_page(struct domain *d, unsigned long gpfn, unsigned long */ /* Guest phsyical address of shared_info */ #define IA64_SHARED_INFO_PADDR (1UL << 40) +/* Guest phsyical address of mapped_regs */ +#define IA64_XMAPPEDREGS_BASE_PADDR (IA64_SHARED_INFO_PADDR + XSI_SIZE) +#define IA64_XMAPPEDREGS_PADDR(vcpu_id) \ + (IA64_XMAPPEDREGS_BASE_PADDR + \ + (vcpu_id) * max_t(unsigned long, PAGE_SIZE, XMAPPEDREGS_SIZE)) /* Guest physical address of the grant table. */ -#define IA64_GRANT_TABLE_PADDR (IA64_SHARED_INFO_PADDR + XSI_SIZE) +#define IA64_GRANT_TABLE_PADDR IA64_XMAPPEDREGS_PADDR(NR_CPUS) #define gnttab_shared_maddr(d, t, i) \ virt_to_maddr((char*)(t)->shared + ((i) << PAGE_SHIFT)) From ab41734c626498d7619c0038cd2de8e269fb1e23 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 14:56:01 -0700 Subject: [PATCH 252/282] [IA64] Domain save fix for foreign domain page mapping semantics change Signed-off-by: Isaku Yamahata --- tools/libxc/ia64/xc_ia64_linux_save.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_linux_save.c b/tools/libxc/ia64/xc_ia64_linux_save.c index d98725445a..034dc35f43 100644 --- a/tools/libxc/ia64/xc_ia64_linux_save.c +++ b/tools/libxc/ia64/xc_ia64_linux_save.c @@ -347,13 +347,13 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, page_array[N], N, max_pfn); mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, - PROT_READ|PROT_WRITE, page_array[N]); + PROT_READ|PROT_WRITE, N); if (mem == NULL) { /* The page may have move. It will be remarked dirty. FIXME: to be tracked. */ - fprintf(stderr, "cannot map page %lx: %s\n", - page_array[N], safe_strerror(errno)); + fprintf(stderr, "cannot map mfn page %lx gpfn %lx: %s\n", + page_array[N], N, safe_strerror(errno)); continue; } From a3c1e7b15fb1a1ea71bf0f12eb18856bcf13595b Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 15:00:49 -0700 Subject: [PATCH 253/282] [IA64] xc_ia64_linux_restore fix for new foreign domain page mapping semantics Signed-off-by: Isaku Yamahata --- tools/libxc/ia64/xc_ia64_linux_restore.c | 68 +++++++++++------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_linux_restore.c b/tools/libxc/ia64/xc_ia64_linux_restore.c index e6aed35ead..5662805e16 100644 --- a/tools/libxc/ia64/xc_ia64_linux_restore.c +++ b/tools/libxc/ia64/xc_ia64_linux_restore.c @@ -63,7 +63,7 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, { DECLARE_DOMCTL; int rc = 1, i; - unsigned long mfn, pfn; + unsigned long gmfn; unsigned long ver; /* The new domain's shared-info frame number. */ @@ -99,28 +99,29 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, return 1; } - /* Get the domain's shared-info frame. */ - domctl.cmd = XEN_DOMCTL_getdomaininfo; - domctl.domain = (domid_t)dom; - if (xc_domctl(xc_handle, &domctl) < 0) { - ERROR("Could not get information on new domain"); - goto out; - } - shared_info_frame = domctl.u.getdomaininfo.shared_info_frame; - if (xc_domain_setmaxmem(xc_handle, dom, PFN_TO_KB(max_pfn)) != 0) { errno = ENOMEM; goto out; } - if (xc_domain_memory_increase_reservation(xc_handle, dom, max_pfn, - 0, 0, NULL) != 0) { - ERROR("Failed to increase reservation by %ld KB", PFN_TO_KB(max_pfn)); - errno = ENOMEM; + /* Get pages. */ + page_array = malloc(max_pfn * sizeof(unsigned long)); + if (page_array == NULL) { + ERROR("Could not allocate memory"); goto out; } - DPRINTF("Increased domain reservation by %ld KB\n", PFN_TO_KB(max_pfn)); + for ( i = 0; i < max_pfn; i++ ) + page_array[i] = i; + + if ( xc_domain_memory_populate_physmap(xc_handle, dom, max_pfn, + 0, 0, page_array) ) + { + ERROR("Failed to allocate memory for %ld KB to dom %d.\n", + PFN_TO_KB(max_pfn), dom); + goto out; + } + DPRINTF("Allocated memory by %ld KB\n", PFN_TO_KB(max_pfn)); if (!read_exact(io_fd, &domctl.u.arch_setup, sizeof(domctl.u.arch_setup))) { ERROR("read: domain setup"); @@ -138,34 +139,28 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, if (xc_domctl(xc_handle, &domctl)) goto out; - /* Get pages. */ - page_array = malloc(max_pfn * sizeof(unsigned long)); - if (page_array == NULL ) { - ERROR("Could not allocate memory"); - goto out; - } - - if (xc_ia64_get_pfn_list(xc_handle, dom, page_array, - 0, max_pfn) != max_pfn) { - ERROR("Could not get the page frame list"); + /* Get the domain's shared-info frame. */ + domctl.cmd = XEN_DOMCTL_getdomaininfo; + domctl.domain = (domid_t)dom; + if (xc_domctl(xc_handle, &domctl) < 0) { + ERROR("Could not get information on new domain"); goto out; } + shared_info_frame = domctl.u.getdomaininfo.shared_info_frame; DPRINTF("Reloading memory pages: 0%%\n"); while (1) { - if (!read_exact(io_fd, &mfn, sizeof(unsigned long))) { + if (!read_exact(io_fd, &gmfn, sizeof(unsigned long))) { ERROR("Error when reading batch size"); goto out; } - if (mfn == INVALID_MFN) + if (gmfn == INVALID_MFN) break; - pfn = page_array[mfn]; + //DPRINTF("xc_linux_restore: page %lu/%lu at %lx\n", gmfn, max_pfn, pfn); - //DPRINTF("xc_linux_restore: page %lu/%lu at %lx\n", mfn, max_pfn, pfn); - - if (read_page(xc_handle, io_fd, dom, page_array[mfn]) < 0) + if (read_page(xc_handle, io_fd, dom, gmfn) < 0) goto out; } @@ -279,19 +274,19 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, for (i = 0; i < MAX_VIRT_CPUS; i++) shared_info->vcpu_info[i].evtchn_pending_sel = 0; - mfn = page_array[shared_info->arch.start_info_pfn]; + gmfn = shared_info->arch.start_info_pfn; munmap (shared_info, PAGE_SIZE); /* Uncanonicalise the suspend-record frame number and poke resume rec. */ start_info = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, - PROT_READ | PROT_WRITE, mfn); + PROT_READ | PROT_WRITE, gmfn); start_info->nr_pages = max_pfn; start_info->shared_info = shared_info_frame << PAGE_SHIFT; start_info->flags = 0; - *store_mfn = page_array[start_info->store_mfn]; + *store_mfn = start_info->store_mfn; start_info->store_evtchn = store_evtchn; - *console_mfn = page_array[start_info->console.domU.mfn]; + *console_mfn = start_info->console.domU.mfn; start_info->console.domU.evtchn = console_evtchn; munmap(start_info, PAGE_SIZE); @@ -315,7 +310,8 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, if ((rc != 0) && (dom != 0)) xc_domain_destroy(xc_handle, dom); - free (page_array); + if (page_array != NULL) + free(page_array); DPRINTF("Restore exit with rc=%d\n", rc); From 9791f98d8abf4d11f327026b12ea8b417efbd4fb Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Thu, 7 Dec 2006 15:02:37 -0700 Subject: [PATCH 254/282] [IA64] allow foreign domain page mapping of DOMID_XEN/DOMID_IO DOMID_XEN is used by xenmon, xentrace. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/mm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index dbf1908c18..0a5acc0636 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -1295,11 +1295,13 @@ __dom0vp_add_physmap(struct domain* d, unsigned long gpfn, if (unlikely(rd == d)) goto out1; - if (is_gmfn) { - if (domid == DOMID_XEN || domid == DOMID_IO) - goto out1; + /* + * DOMID_XEN and DOMID_IO don't have their own p2m table. + * It can be considered that their p2m conversion is p==m. + */ + if (likely(is_gmfn && domid != DOMID_XEN && domid != DOMID_IO)) mfn = gmfn_to_mfn(rd, mfn_or_gmfn); - } else + else mfn = mfn_or_gmfn; if (unlikely(!mfn_valid(mfn) || get_page(mfn_to_page(mfn), rd) == 0)) goto out1; From e80c00aa787316a5080496b47418d91eaf3dccf5 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 09:19:37 +0000 Subject: [PATCH 255/282] [LINUX] Clean up and clarify find_unbound_irq(). Signed-off-by: Keir Fraser --- .../drivers/xen/core/evtchn.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c b/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c index d596da3888..445cacf785 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/evtchn.c @@ -244,24 +244,22 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs) static int find_unbound_irq(void) { - int irq; + static int warned; + int dynirq, irq; - /* Only allocate from dynirq range */ - for (irq = DYNIRQ_BASE; irq < NR_IRQS; irq++) + for (dynirq = 0; dynirq < NR_DYNIRQS; dynirq++) { + irq = dynirq_to_irq(dynirq); if (irq_bindcount[irq] == 0) - break; - - if (irq == NR_IRQS) { - static int warned; - if (!warned) { - warned = 1; - printk(KERN_WARNING "No available IRQ to bind to: " - "increase NR_IRQS!\n"); - } - return -ENOSPC; + return irq; } - return irq; + if (!warned) { + warned = 1; + printk(KERN_WARNING "No available IRQ to bind to: " + "increase NR_DYNIRQS.\n"); + } + + return -ENOSPC; } static int bind_evtchn_to_irq(unsigned int evtchn) From 27c982df5e2b051941188900874b664092a0482c Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 09:27:39 +0000 Subject: [PATCH 256/282] [LINUX] Make xb_waitq static. Signed-off-by: Jan Beulich --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c | 2 +- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c index f0e42ba715..e5af661c87 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -52,7 +52,7 @@ extern void xenbus_probe(void *); extern int xenstored_ready; static DECLARE_WORK(probe_work, xenbus_probe, NULL); -DECLARE_WAIT_QUEUE_HEAD(xb_waitq); +static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs) { diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h index 9599d037c4..b54d168cbb 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.h @@ -38,7 +38,6 @@ int xb_init_comms(void); int xb_write(const void *data, unsigned len); int xb_read(void *data, unsigned len); int xs_input_avail(void); -extern wait_queue_head_t xb_waitq; extern struct xenstore_domain_interface *xen_store_interface; extern int xen_store_evtchn; From 03ba7e6e162e8f5fa1532dad3eff40e3ce027a22 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 09:32:42 +0000 Subject: [PATCH 257/282] Make XEN_DOMCTL_getdomaininfo return shared_info_frame in gmfn not mfn. Signed-off-by: Isaku Yamahata --- xen/common/domctl.c | 2 +- xen/include/public/domctl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/common/domctl.c b/xen/common/domctl.c index bf6b8473aa..b05ecd1099 100644 --- a/xen/common/domctl.c +++ b/xen/common/domctl.c @@ -126,7 +126,7 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info) info->tot_pages = d->tot_pages; info->max_pages = d->max_pages; - info->shared_info_frame = __pa(d->shared_info) >> PAGE_SHIFT; + info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT); memcpy(info->handle, d->handle, sizeof(xen_domain_handle_t)); } diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 37618ad827..da0b5b2868 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -93,7 +93,7 @@ struct xen_domctl_getdomaininfo { uint32_t flags; /* XEN_DOMINF_* */ uint64_t tot_pages; uint64_t max_pages; - uint64_t shared_info_frame; /* MFN of shared_info struct */ + uint64_t shared_info_frame; /* GMFN of shared_info struct */ uint64_t cpu_time; uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */ uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */ From ebeefe4ef6c680c49f84f059265ec4b7f6b0d250 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 09:34:24 +0000 Subject: [PATCH 258/282] [LINUX] Make CONFIG_XEN_FRAMEBUFFER=m build properly. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c index 0111e8e3a2..a11140bda0 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c @@ -289,6 +289,7 @@ int xenbus_free_evtchn(struct xenbus_device *dev, int port) return err; } +EXPORT_SYMBOL_GPL(xenbus_free_evtchn); enum xenbus_state xenbus_read_driver_state(const char *path) From 7953e4aa37ebcdb7ad6603512d798de0dd5df77e Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 09:35:00 +0000 Subject: [PATCH 259/282] [LINUX] CONFIG_XEN_BACKEND=m build properly. Signed-off-by: Jan Beulich --- linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile | 10 +++------- linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile b/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile index ce5acc2457..d7091dcbcb 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile @@ -1,13 +1,9 @@ -obj-y += xenbus.o +obj-y += xenbus_client.o xenbus_comms.o xenbus_xs.o xenbus_probe.o obj-$(CONFIG_XEN_BACKEND) += xenbus_be.o xenbus_be-objs = xenbus_be-objs += xenbus_backend_client.o -xenbus-objs = -xenbus-objs += xenbus_client.o -xenbus-objs += xenbus_comms.o -xenbus-objs += xenbus_xs.o -xenbus-objs += xenbus_probe.o -obj-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o +xenbus-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o +obj-y += $(xenbus-y) $(xenbus-m) obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o diff --git a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h index 2d2e567826..417b23e184 100644 --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h @@ -34,7 +34,7 @@ #ifndef _XENBUS_PROBE_H #define _XENBUS_PROBE_H -#ifdef CONFIG_XEN_BACKEND +#if defined(CONFIG_XEN_BACKEND) || defined(CONFIG_XEN_BACKEND_MODULE) extern void xenbus_backend_suspend(int (*fn)(struct device *, void *)); extern void xenbus_backend_resume(int (*fn)(struct device *, void *)); extern void xenbus_backend_probe_and_watch(void); From e0abcedc4994deeb7119eeed4f709713e46ab2cc Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Fri, 8 Dec 2006 10:32:48 +0000 Subject: [PATCH 260/282] Download and symlink the i386 version of the ramdisk when running on x86_64. This means that people don't need to explicitly set BR_ARCH. Signed-off-by: Ewan Mellor --- tools/xm-test/ramdisk/Makefile.am | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/xm-test/ramdisk/Makefile.am b/tools/xm-test/ramdisk/Makefile.am index 14bfc9267c..b6c59d60e5 100644 --- a/tools/xm-test/ramdisk/Makefile.am +++ b/tools/xm-test/ramdisk/Makefile.am @@ -34,6 +34,7 @@ HVM_SCRIPT = bin/create_disk_image XMTEST_MAJ_VER = $(shell echo @PACKAGE_VERSION@ | perl -pe 's/(\d+)\.(\d+)\.\d+/\1.\2/') XMTEST_VER_IMG = initrd-$(XMTEST_MAJ_VER)-$(BR_ARCH).img +XMTEST_DL_IMG = $(shell echo $(XMTEST_VER_IMG) | sed -e 's/x86_64/i386/g') EXTRA_ROOT_DIRS = sys @@ -83,7 +84,12 @@ disk.img: existing existing: @if [ -n "$(INITRD)" ] && [ ! -f $(XMTEST_VER_IMG) ] ; then \ - wget $(INITRD)/$(XMTEST_VER_IMG); \ + if [ ! -f $(XMTEST_DL_IMG) ] ; then \ + wget $(INITRD)/$(XMTEST_DL_IMG); \ + fi; \ + if [ "$(XMTEST_DL_IMG)" != "$(XMTEST_VER_IMG)" ] ; then \ + ln -s $(XMTEST_DL_IMG) $(XMTEST_VER_IMG); \ + fi \ fi @if [ -f $(XMTEST_VER_IMG) ] ; then \ ln -sf $(XMTEST_VER_IMG) initrd.img; \ From 9ccd4175a4c9611870e1aa0fabaf965fde72bd9d Mon Sep 17 00:00:00 2001 From: Steven Hand Date: Fri, 8 Dec 2006 10:48:46 +0000 Subject: [PATCH 261/282] Fix potential minor memory leak. Signed-off-by: Steven Hand --- xen/arch/x86/mm/shadow/multi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 211b98b2ed..d9d9bd1c70 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -2762,6 +2762,7 @@ static int sh_page_fault(struct vcpu *v, * shadow_set_l*e(), which will have crashed the guest. * Get out of the fault handler immediately. */ ASSERT(test_bit(_DOMF_dying, &d->domain_flags)); + unmap_walk(v, &gw); shadow_unlock(d); return 0; } From a3b9408bafc6cd2a23c0e41676d1abab5a906c9a Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 8 Dec 2006 11:08:26 +0000 Subject: [PATCH 262/282] [XEND] Fix xm vcpu-set when decrementing VCPU count Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 5 ++++- tools/python/xen/xend/XendDomainInfo.py | 14 +++++++++++--- tools/python/xen/xm/main.py | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 74ff06284d..9896254f32 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -632,6 +632,9 @@ class XendConfig(dict): self['memory_dynamic_max'] = self['memory_static_max'] self['memory_dynamic_min'] = self['memory_static_min'] + # make sure max_vcpu_id is set correctly + self['max_vcpu_id'] = self['vcpus_number'] - 1 + # set device references in the configuration self['devices'] = cfg.get('devices', {}) @@ -714,7 +717,7 @@ class XendConfig(dict): _set_cfg_if_exists('on_xend_stop') _set_cfg_if_exists('on_xend_start') _set_cfg_if_exists('vcpu_avail') - _set_cfg_if_exists('max_vcpu_id') # TODO, deprecated? + _set_cfg_if_exists('max_vcpu_id') # needed for vcpuDomDetails # Parse and store runtime configuration _set_cfg_if_exists('start_time') diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 29ce17083c..c0a66aaf67 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -876,10 +876,18 @@ class XendDomainInfo: def setVCpuCount(self, vcpus): self.info['vcpu_avail'] = (1 << vcpus) - 1 - self.info['vcpus_number'] = vcpus self.storeVm('vcpu_avail', self.info['vcpu_avail']) - self.storeVm('vcpus', self.info['vcpus_number']) - self._writeDom(self._vcpuDomDetails()) + # update dom differently depending on whether we are adjusting + # vcpu number up or down, otherwise _vcpuDomDetails does not + # disable the vcpus + if self.info['vcpus_number'] > vcpus: + # decreasing + self._writeDom(self._vcpuDomDetails()) + self.info['vcpus_number'] = vcpus + else: + # same or increasing + self.info['vcpus_number'] = vcpus + self._writeDom(self._vcpuDomDetails()) def getLabel(self): return security.get_security_info(self.info, 'label') diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 6850061908..dff8253639 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -643,7 +643,7 @@ def parse_doms_info(info): 'domid' : get_info('domid', str, ''), 'name' : get_info('name', str, '??'), 'mem' : get_info('memory_dynamic_min', int, 0), - 'vcpus' : get_info('vcpus', int, 0), + 'vcpus' : get_info('online_vcpus', int, 0), 'state' : get_info('state', str, ''), 'cpu_time' : get_info('cpu_time', float, 0), 'up_time' : up_time, From 43ff8f0aefb427bc6390c872e5c2a3a800189e1f Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 11:30:30 +0000 Subject: [PATCH 263/282] [XEN] Implement XENMEM_set_memory_map, which specifies memory map to be returned by XENMEM_memory_map. Hook this into the domain builder. Based on a patch by Glauber de Oliveira Costa Signed-off-by: Keir Fraser --- tools/libxc/xc_domain.c | 46 ++++++++++++++++++++++++++++++ tools/libxc/xenctrl.h | 4 +++ tools/python/xen/lowlevel/xc/xc.c | 23 +++++++++++++++ tools/python/xen/xend/image.py | 10 ++++++- xen/arch/x86/mm.c | 47 ++++++++++++++++++++++++++++++- xen/include/asm-x86/domain.h | 10 +++---- xen/include/public/memory.h | 17 ++++++++++- 7 files changed, 149 insertions(+), 8 deletions(-) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index b63e172a22..82aef99ccc 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -316,6 +316,52 @@ int xc_domain_setmaxmem(int xc_handle, return do_domctl(xc_handle, &domctl); } +#if defined(__i386__) || defined(__x86_64__) +#include +int xc_domain_set_memmap_limit(int xc_handle, + uint32_t domid, + unsigned long map_limitkb) +{ + int rc; + + struct xen_foreign_memory_map fmap = { + .domid = domid, + .map = { .nr_entries = 1 } + }; + + struct e820entry e820 = { + .addr = 0, + .size = (uint64_t)map_limitkb << 10, + .type = E820_RAM + }; + + set_xen_guest_handle(fmap.map.buffer, &e820); + + if ( lock_pages(&fmap, sizeof(fmap)) || lock_pages(&e820, sizeof(e820)) ) + { + PERROR("Could not lock memory for Xen hypercall"); + rc = -1; + goto out; + } + + rc = xc_memory_op(xc_handle, XENMEM_set_memory_map, &fmap); + + out: + unlock_pages(&fmap, sizeof(fmap)); + unlock_pages(&e820, sizeof(e820)); + return rc; +} +#else +int xc_domain_set_memmap_limit(int xc_handle, + uint32_t domid, + unsigned long map_limitkb) +{ + PERROR("Function not implemented"); + errno = ENOSYS; + return -1; +} +#endif + int xc_domain_set_time_offset(int xc_handle, uint32_t domid, int32_t time_offset_seconds) diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index d0a9f5db97..00fa713562 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -419,6 +419,10 @@ int xc_domain_setmaxmem(int xc_handle, uint32_t domid, unsigned int max_memkb); +int xc_domain_set_memmap_limit(int xc_handle, + uint32_t domid, + unsigned long map_limitkb); + int xc_domain_set_time_offset(int xc_handle, uint32_t domid, int32_t time_offset_seconds); diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index e74a882fe0..0d68d89f28 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -758,6 +758,21 @@ static PyObject *pyxc_domain_setmaxmem(XcObject *self, PyObject *args) return zero; } +static PyObject *pyxc_domain_set_memmap_limit(XcObject *self, PyObject *args) +{ + uint32_t dom; + unsigned int maplimit_kb; + + if ( !PyArg_ParseTuple(args, "ii", &dom, &maplimit_kb) ) + return NULL; + + if ( xc_domain_set_memmap_limit(self->xc_handle, dom, maplimit_kb) != 0 ) + return pyxc_error_to_exception(); + + Py_INCREF(zero); + return zero; +} + static PyObject *pyxc_domain_memory_increase_reservation(XcObject *self, PyObject *args, PyObject *kwds) @@ -1141,6 +1156,14 @@ static PyMethodDef pyxc_methods[] = { " maxmem_kb [int]: .\n" "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_set_memmap_limit", + (PyCFunction)pyxc_domain_set_memmap_limit, + METH_VARARGS, "\n" + "Set a domain's physical memory mappping limit\n" + " dom [int]: Identifier of domain.\n" + " map_limitkb [int]: .\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + { "domain_memory_increase_reservation", (PyCFunction)pyxc_domain_memory_increase_reservation, METH_VARARGS | METH_KEYWORDS, "\n" diff --git a/tools/python/xen/xend/image.py b/tools/python/xen/xend/image.py index 29eea9dc55..2ccc8615e9 100644 --- a/tools/python/xen/xend/image.py +++ b/tools/python/xen/xend/image.py @@ -548,6 +548,14 @@ class X86_HVM_ImageHandler(HVMImageHandler): return max(4 * (256 * self.vm.getVCpuCount() + 2 * (maxmem_kb / 1024)), shadow_mem_kb) +class X86_Linux_ImageHandler(LinuxImageHandler): + + def buildDomain(self): + # set physical mapping limit + # add an 8MB slack to balance backend allocations. + mem_kb = self.getRequiredInitialReservation() + (8 * 1024) + xc.domain_set_memmap_limit(self.vm.getDomid(), mem_kb) + return LinuxImageHandler.buildDomain(self) _handlers = { "powerpc": { @@ -558,7 +566,7 @@ _handlers = { "hvm": IA64_HVM_ImageHandler, }, "x86": { - "linux": LinuxImageHandler, + "linux": X86_Linux_ImageHandler, "hvm": X86_HVM_ImageHandler, }, } diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 9a965f982b..4fd69400f3 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -2978,9 +2978,54 @@ long arch_memory_op(int op, XEN_GUEST_HANDLE(void) arg) break; } + case XENMEM_set_memory_map: + { + struct xen_foreign_memory_map fmap; + struct domain *d; + int rc; + + if ( copy_from_guest(&fmap, arg, 1) ) + return -EFAULT; + + if ( fmap.map.nr_entries > ARRAY_SIZE(d->arch.e820) ) + return -EINVAL; + + if ( fmap.domid == DOMID_SELF ) + { + d = current->domain; + get_knownalive_domain(d); + } + else if ( !IS_PRIV(current->domain) ) + return -EPERM; + else if ( (d = find_domain_by_id(fmap.domid)) == NULL ) + return -ESRCH; + + rc = copy_from_guest(&d->arch.e820[0], fmap.map.buffer, + fmap.map.nr_entries) ? -EFAULT : 0; + d->arch.nr_e820 = fmap.map.nr_entries; + + put_domain(d); + return rc; + } + case XENMEM_memory_map: { - return -ENOSYS; + struct xen_memory_map map; + struct domain *d = current->domain; + + /* Backwards compatibility. */ + if ( d->arch.nr_e820 == 0 ) + return -ENOSYS; + + if ( copy_from_guest(&map, arg, 1) ) + return -EFAULT; + + map.nr_entries = min(map.nr_entries, d->arch.nr_e820); + if ( copy_to_guest(map.buffer, &d->arch.e820[0], map.nr_entries) || + copy_to_guest(arg, &map, 1) ) + return -EFAULT; + + return 0; } case XENMEM_machine_memory_map: diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 20793910ba..efda6dd263 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -5,6 +5,7 @@ #include #include #include +#include struct trap_bounce { unsigned long error_code; @@ -100,11 +101,7 @@ struct arch_domain /* I/O-port admin-specified access capabilities. */ struct rangeset *ioport_caps; - /* HVM stuff */ - struct hvm_domain hvm_domain; - - /* Shadow-translated guest: Pseudophys base address of reserved area. */ - unsigned long first_reserved_pfn; + struct hvm_domain hvm_domain; struct shadow_domain shadow; @@ -113,6 +110,9 @@ struct arch_domain /* Highest guest frame that's ever been mapped in the p2m */ unsigned long max_mapped_pfn; + /* Pseudophysical e820 map (XENMEM_memory_map). */ + struct e820entry e820[3]; + unsigned int nr_e820; } __cacheline_aligned; #ifdef CONFIG_X86_PAE diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index e28ed12620..acbc89b7e7 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -222,7 +222,8 @@ DEFINE_XEN_GUEST_HANDLE(xen_translate_gpfn_list_t); /* * Returns the pseudo-physical memory map as it was when the domain - * was started. + * was started (specified by XENMEM_set_memory_map). + * arg == addr of xen_memory_map_t. */ #define XENMEM_memory_map 9 struct xen_memory_map { @@ -245,9 +246,23 @@ DEFINE_XEN_GUEST_HANDLE(xen_memory_map_t); /* * Returns the real physical memory map. Passes the same structure as * XENMEM_memory_map. + * arg == addr of xen_memory_map_t. */ #define XENMEM_machine_memory_map 10 +/* + * Set the pseudo-physical memory map of a domain, as returned by + * XENMEM_memory_map. + * arg == addr of xen_foreign_memory_map_t. + */ +#define XENMEM_set_memory_map 13 +struct xen_foreign_memory_map { + domid_t domid; + struct xen_memory_map map; +}; +typedef struct xen_foreign_memory_map xen_foreign_memory_map_t; +DEFINE_XEN_GUEST_HANDLE(xen_foreign_memory_map_t); + #endif /* __XEN_PUBLIC_MEMORY_H__ */ /* From e793ba7d4ead6b2a55a984d4f5c23da971bbfc67 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 8 Dec 2006 11:46:48 +0000 Subject: [PATCH 264/282] [LINUX] Kexec: Do not bug if a kexec hypercall fails. This is non fatal since we can recover and boot without kexec functionality. Signed-off-by: Ian Campbell --- .../drivers/xen/core/machine_kexec.c | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c index 1f4a828e55..5e6b58b390 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -20,7 +20,7 @@ void xen_machine_kexec_setup_resources(void) { xen_kexec_range_t range; struct resource *res; - int err, k = 0; + int k = 0; if (!is_initial_xendomain()) return; @@ -32,26 +32,21 @@ void xen_machine_kexec_setup_resources(void) range.range = KEXEC_RANGE_MA_CPU; range.nr = k; - /* - * Anything other than EINVAL or success indictates - * that we are not running on a hypervisor which - * supports kexec. - */ - err = HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range); - if (err == -EINVAL) + if(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) break; - else if (err) - return; k++; } + if (k == 0) + return; + xen_max_nr_phys_cpus = k; /* allocate xen_phys_cpus */ xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource)); - BUG_ON(!xen_phys_cpus); + BUG_ON(xen_phys_cpus == NULL); /* fill in xen_phys_cpus with per-cpu crash note information */ @@ -61,7 +56,7 @@ void xen_machine_kexec_setup_resources(void) range.nr = k; if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) - BUG(); + goto err; res = xen_phys_cpus + k; @@ -78,7 +73,7 @@ void xen_machine_kexec_setup_resources(void) range.range = KEXEC_RANGE_MA_XEN; if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) - BUG(); + goto err; xen_hypervisor_res.name = "Hypervisor code and data"; xen_hypervisor_res.start = range.start; @@ -91,12 +86,23 @@ void xen_machine_kexec_setup_resources(void) range.range = KEXEC_RANGE_MA_CRASH; if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range)) - BUG(); + return; if (range.size) { crashk_res.start = range.start; crashk_res.end = range.start + range.size - 1; } + + return; + + err: + /* + * It isn't possible to free xen_phys_cpus this early in the + * boot. Since failure at this stage is unexpected and the + * amount is small we leak the memory. + */ + xen_max_nr_phys_cpus = 0; + return; } void xen_machine_kexec_register_resources(struct resource *res) From 5a4af387e35b5e86c5e2b4a53e8f1784125c5dd8 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 8 Dec 2006 11:47:09 +0000 Subject: [PATCH 265/282] [LINUX] kexec: remove patches which are not straight backports. Their contents will be added to the sparse tree in a subsequent patch. Changes to kernel/sys.c in kexec-generic.patch remain for now. These will be taken care of in a later patch. Signed-off-by: Ian Campbell --- patches/linux-2.6.16.33/kexec-generic.patch | 213 ----------------- .../linux-2.6.19-rc1-kexec-xen-i386.patch | 108 --------- .../linux-2.6.19-rc1-kexec-xen-x86_64.patch | 219 ------------------ patches/linux-2.6.16.33/series | 2 - 4 files changed, 542 deletions(-) delete mode 100644 patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch delete mode 100644 patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch diff --git a/patches/linux-2.6.16.33/kexec-generic.patch b/patches/linux-2.6.16.33/kexec-generic.patch index 2e01a7aab0..a85d546e4d 100644 --- a/patches/linux-2.6.16.33/kexec-generic.patch +++ b/patches/linux-2.6.16.33/kexec-generic.patch @@ -1,216 +1,3 @@ ---- 0001/include/linux/kexec.h -+++ work/include/linux/kexec.h -@@ -31,6 +31,13 @@ - #error KEXEC_ARCH not defined - #endif - -+#ifndef KEXEC_ARCH_HAS_PAGE_MACROS -+#define kexec_page_to_pfn(page) page_to_pfn(page) -+#define kexec_pfn_to_page(pfn) pfn_to_page(pfn) -+#define kexec_virt_to_phys(addr) virt_to_phys(addr) -+#define kexec_phys_to_virt(addr) phys_to_virt(addr) -+#endif -+ - /* - * This structure is used to hold the arguments that are used when loading - * kernel binaries. -@@ -91,6 +98,13 @@ struct kimage { - extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; - extern int machine_kexec_prepare(struct kimage *image); - extern void machine_kexec_cleanup(struct kimage *image); -+#ifdef CONFIG_XEN -+extern int xen_machine_kexec_load(struct kimage *image); -+extern void xen_machine_kexec_unload(struct kimage *image); -+extern NORET_TYPE void xen_machine_kexec(struct kimage *image) ATTRIB_NORET; -+extern void xen_machine_kexec_setup_resources(void); -+extern void xen_machine_kexec_register_resources(struct resource *res); -+#endif - extern asmlinkage long sys_kexec_load(unsigned long entry, - unsigned long nr_segments, - struct kexec_segment __user *segments, ---- 0001/kernel/kexec.c -+++ work/kernel/kexec.c -@@ -403,7 +403,7 @@ static struct page *kimage_alloc_normal_ - pages = kimage_alloc_pages(GFP_KERNEL, order); - if (!pages) - break; -- pfn = page_to_pfn(pages); -+ pfn = kexec_page_to_pfn(pages); - epfn = pfn + count; - addr = pfn << PAGE_SHIFT; - eaddr = epfn << PAGE_SHIFT; -@@ -437,6 +437,7 @@ static struct page *kimage_alloc_normal_ - return pages; - } - -+#ifndef CONFIG_XEN - static struct page *kimage_alloc_crash_control_pages(struct kimage *image, - unsigned int order) - { -@@ -490,7 +491,7 @@ static struct page *kimage_alloc_crash_c - } - /* If I don't overlap any segments I have found my hole! */ - if (i == image->nr_segments) { -- pages = pfn_to_page(hole_start >> PAGE_SHIFT); -+ pages = kexec_pfn_to_page(hole_start >> PAGE_SHIFT); - break; - } - } -@@ -517,6 +518,13 @@ struct page *kimage_alloc_control_pages( - - return pages; - } -+#else /* !CONFIG_XEN */ -+struct page *kimage_alloc_control_pages(struct kimage *image, -+ unsigned int order) -+{ -+ return kimage_alloc_normal_control_pages(image, order); -+} -+#endif - - static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) - { -@@ -532,7 +540,7 @@ static int kimage_add_entry(struct kimag - return -ENOMEM; - - ind_page = page_address(page); -- *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; -+ *image->entry = kexec_virt_to_phys(ind_page) | IND_INDIRECTION; - image->entry = ind_page; - image->last_entry = ind_page + - ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); -@@ -593,13 +601,13 @@ static int kimage_terminate(struct kimag - #define for_each_kimage_entry(image, ptr, entry) \ - for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ - ptr = (entry & IND_INDIRECTION)? \ -- phys_to_virt((entry & PAGE_MASK)): ptr +1) -+ kexec_phys_to_virt((entry & PAGE_MASK)): ptr +1) - - static void kimage_free_entry(kimage_entry_t entry) - { - struct page *page; - -- page = pfn_to_page(entry >> PAGE_SHIFT); -+ page = kexec_pfn_to_page(entry >> PAGE_SHIFT); - kimage_free_pages(page); - } - -@@ -611,6 +619,10 @@ static void kimage_free(struct kimage *i - if (!image) - return; - -+#ifdef CONFIG_XEN -+ xen_machine_kexec_unload(image); -+#endif -+ - kimage_free_extra_pages(image); - for_each_kimage_entry(image, ptr, entry) { - if (entry & IND_INDIRECTION) { -@@ -686,7 +698,7 @@ static struct page *kimage_alloc_page(st - * have a match. - */ - list_for_each_entry(page, &image->dest_pages, lru) { -- addr = page_to_pfn(page) << PAGE_SHIFT; -+ addr = kexec_page_to_pfn(page) << PAGE_SHIFT; - if (addr == destination) { - list_del(&page->lru); - return page; -@@ -701,12 +713,12 @@ static struct page *kimage_alloc_page(st - if (!page) - return NULL; - /* If the page cannot be used file it away */ -- if (page_to_pfn(page) > -+ if (kexec_page_to_pfn(page) > - (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { - list_add(&page->lru, &image->unuseable_pages); - continue; - } -- addr = page_to_pfn(page) << PAGE_SHIFT; -+ addr = kexec_page_to_pfn(page) << PAGE_SHIFT; - - /* If it is the destination page we want use it */ - if (addr == destination) -@@ -729,7 +741,7 @@ static struct page *kimage_alloc_page(st - struct page *old_page; - - old_addr = *old & PAGE_MASK; -- old_page = pfn_to_page(old_addr >> PAGE_SHIFT); -+ old_page = kexec_pfn_to_page(old_addr >> PAGE_SHIFT); - copy_highpage(page, old_page); - *old = addr | (*old & ~PAGE_MASK); - -@@ -779,7 +791,7 @@ static int kimage_load_normal_segment(st - result = -ENOMEM; - goto out; - } -- result = kimage_add_page(image, page_to_pfn(page) -+ result = kimage_add_page(image, kexec_page_to_pfn(page) - << PAGE_SHIFT); - if (result < 0) - goto out; -@@ -811,6 +823,7 @@ out: - return result; - } - -+#ifndef CONFIG_XEN - static int kimage_load_crash_segment(struct kimage *image, - struct kexec_segment *segment) - { -@@ -833,7 +846,7 @@ static int kimage_load_crash_segment(str - char *ptr; - size_t uchunk, mchunk; - -- page = pfn_to_page(maddr >> PAGE_SHIFT); -+ page = kexec_pfn_to_page(maddr >> PAGE_SHIFT); - if (page == 0) { - result = -ENOMEM; - goto out; -@@ -881,6 +894,13 @@ static int kimage_load_segment(struct ki - - return result; - } -+#else /* CONFIG_XEN */ -+static int kimage_load_segment(struct kimage *image, -+ struct kexec_segment *segment) -+{ -+ return kimage_load_normal_segment(image, segment); -+} -+#endif - - /* - * Exec Kernel system call: for obvious reasons only root may call it. -@@ -991,6 +1011,11 @@ asmlinkage long sys_kexec_load(unsigned - if (result) - goto out; - } -+#ifdef CONFIG_XEN -+ result = xen_machine_kexec_load(image); -+ if (result) -+ goto out; -+#endif - /* Install the new kernel, and Uninstall the old */ - image = xchg(dest_image, image); - -@@ -1045,7 +1070,6 @@ void crash_kexec(struct pt_regs *regs) - struct kimage *image; - int locked; - -- - /* Take the kexec_lock here to prevent sys_kexec_load - * running on one cpu from replacing the crash kernel - * we are using after a panic on a different cpu. -@@ -1061,7 +1085,11 @@ void crash_kexec(struct pt_regs *regs) - struct pt_regs fixed_regs; - crash_setup_regs(&fixed_regs, regs); - machine_crash_shutdown(&fixed_regs); -+#ifdef CONFIG_XEN -+ xen_machine_kexec(image); -+#else - machine_kexec(image); -+#endif - } - xchg(&kexec_lock, 0); - } --- 0002/kernel/sys.c +++ work/kernel/sys.c @@ -435,8 +435,12 @@ void kernel_kexec(void) diff --git a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch deleted file mode 100644 index 93480f9528..0000000000 --- a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-i386.patch +++ /dev/null @@ -1,108 +0,0 @@ ---- 0001/arch/i386/kernel/crash.c -+++ work/arch/i386/kernel/crash.c -@@ -90,6 +90,7 @@ static void crash_save_self(struct pt_re - crash_save_this_cpu(regs, cpu); - } - -+#ifndef CONFIG_XEN - #ifdef CONFIG_SMP - static atomic_t waiting_for_crash_ipi; - -@@ -158,6 +159,7 @@ static void nmi_shootdown_cpus(void) - /* There are no cpus to shootdown */ - } - #endif -+#endif /* CONFIG_XEN */ - - void machine_crash_shutdown(struct pt_regs *regs) - { -@@ -174,10 +176,12 @@ void machine_crash_shutdown(struct pt_re - - /* Make a note of crashing cpu. Will be used in NMI callback.*/ - crashing_cpu = smp_processor_id(); -+#ifndef CONFIG_XEN - nmi_shootdown_cpus(); - lapic_shutdown(); - #if defined(CONFIG_X86_IO_APIC) - disable_IO_APIC(); - #endif -+#endif /* CONFIG_XEN */ - crash_save_self(regs); - } ---- 0007/arch/i386/kernel/machine_kexec.c -+++ work/arch/i386/kernel/machine_kexec.c -@@ -19,6 +19,10 @@ - #include - #include - -+#ifdef CONFIG_XEN -+#include -+#endif -+ - #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) - static u32 kexec_pgd[1024] PAGE_ALIGNED; - #ifdef CONFIG_X86_PAE -@@ -28,6 +32,40 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED - static u32 kexec_pte0[1024] PAGE_ALIGNED; - static u32 kexec_pte1[1024] PAGE_ALIGNED; - -+#ifdef CONFIG_XEN -+ -+#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) -+ -+#if PAGES_NR > KEXEC_XEN_NO_PAGES -+#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break -+#endif -+ -+#if PA_CONTROL_PAGE != 0 -+#error PA_CONTROL_PAGE is non zero - Xen support will break -+#endif -+ -+void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) -+{ -+ void *control_page; -+ -+ memset(xki->page_list, 0, sizeof(xki->page_list)); -+ -+ control_page = page_address(image->control_code_page); -+ memcpy(control_page, relocate_kernel, PAGE_SIZE); -+ -+ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); -+ xki->page_list[PA_PGD] = __ma(kexec_pgd); -+#ifdef CONFIG_X86_PAE -+ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); -+ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); -+#endif -+ xki->page_list[PA_PTE_0] = __ma(kexec_pte0); -+ xki->page_list[PA_PTE_1] = __ma(kexec_pte1); -+ -+} -+ -+#endif /* CONFIG_XEN */ -+ - /* - * A architecture hook called to validate the - * proposed image and prepare the control pages ---- 0006/include/asm-i386/kexec.h -+++ work/include/asm-i386/kexec.h -@@ -98,6 +98,20 @@ relocate_kernel(unsigned long indirectio - unsigned long start_address, - unsigned int has_pae) ATTRIB_NORET; - -+ -+/* Under Xen we need to work with machine addresses. These macros give the -+ * machine address of a certain page to the generic kexec code instead of -+ * the pseudo physical address which would be given by the default macros. -+ */ -+ -+#ifdef CONFIG_XEN -+#define KEXEC_ARCH_HAS_PAGE_MACROS -+#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) -+#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) -+#define kexec_virt_to_phys(addr) virt_to_machine(addr) -+#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) -+#endif -+ - #endif /* __ASSEMBLY__ */ - - #endif /* _I386_KEXEC_H */ diff --git a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch b/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch deleted file mode 100644 index c387519889..0000000000 --- a/patches/linux-2.6.16.33/linux-2.6.19-rc1-kexec-xen-x86_64.patch +++ /dev/null @@ -1,219 +0,0 @@ ---- 0001/arch/x86_64/kernel/crash.c -+++ work/arch/x86_64/kernel/crash.c -@@ -92,6 +92,7 @@ static void crash_save_self(struct pt_re - crash_save_this_cpu(regs, cpu); - } - -+#ifndef CONFIG_XEN - #ifdef CONFIG_SMP - static atomic_t waiting_for_crash_ipi; - -@@ -156,6 +157,7 @@ static void nmi_shootdown_cpus(void) - /* There are no cpus to shootdown */ - } - #endif -+#endif /* CONFIG_XEN */ - - void machine_crash_shutdown(struct pt_regs *regs) - { -@@ -173,6 +175,8 @@ void machine_crash_shutdown(struct pt_re - - /* Make a note of crashing cpu. Will be used in NMI callback.*/ - crashing_cpu = smp_processor_id(); -+ -+#ifndef CONFIG_XEN - nmi_shootdown_cpus(); - - if(cpu_has_apic) -@@ -181,6 +185,6 @@ void machine_crash_shutdown(struct pt_re - #if defined(CONFIG_X86_IO_APIC) - disable_IO_APIC(); - #endif -- -+#endif /* CONFIG_XEN */ - crash_save_self(regs); - } ---- 0010/arch/x86_64/kernel/machine_kexec.c -+++ work/arch/x86_64/kernel/machine_kexec.c -@@ -24,6 +24,104 @@ static u64 kexec_pud1[512] PAGE_ALIGNED; - static u64 kexec_pmd1[512] PAGE_ALIGNED; - static u64 kexec_pte1[512] PAGE_ALIGNED; - -+#ifdef CONFIG_XEN -+ -+/* In the case of Xen, override hypervisor functions to be able to create -+ * a regular identity mapping page table... -+ */ -+ -+#include -+#include -+ -+#define x__pmd(x) ((pmd_t) { (x) } ) -+#define x__pud(x) ((pud_t) { (x) } ) -+#define x__pgd(x) ((pgd_t) { (x) } ) -+ -+#define x_pmd_val(x) ((x).pmd) -+#define x_pud_val(x) ((x).pud) -+#define x_pgd_val(x) ((x).pgd) -+ -+static inline void x_set_pmd(pmd_t *dst, pmd_t val) -+{ -+ x_pmd_val(*dst) = x_pmd_val(val); -+} -+ -+static inline void x_set_pud(pud_t *dst, pud_t val) -+{ -+ x_pud_val(*dst) = phys_to_machine(x_pud_val(val)); -+} -+ -+static inline void x_pud_clear (pud_t *pud) -+{ -+ x_pud_val(*pud) = 0; -+} -+ -+static inline void x_set_pgd(pgd_t *dst, pgd_t val) -+{ -+ x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val)); -+} -+ -+static inline void x_pgd_clear (pgd_t * pgd) -+{ -+ x_pgd_val(*pgd) = 0; -+} -+ -+#define X__PAGE_KERNEL_LARGE_EXEC \ -+ _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE -+#define X_KERNPG_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY -+ -+#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) -+ -+#if PAGES_NR > KEXEC_XEN_NO_PAGES -+#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break -+#endif -+ -+#if PA_CONTROL_PAGE != 0 -+#error PA_CONTROL_PAGE is non zero - Xen support will break -+#endif -+ -+void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) -+{ -+ void *control_page; -+ void *table_page; -+ -+ memset(xki->page_list, 0, sizeof(xki->page_list)); -+ -+ control_page = page_address(image->control_code_page) + PAGE_SIZE; -+ memcpy(control_page, relocate_kernel, PAGE_SIZE); -+ -+ table_page = page_address(image->control_code_page); -+ -+ xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); -+ xki->page_list[PA_TABLE_PAGE] = __ma(table_page); -+ -+ xki->page_list[PA_PGD] = __ma(kexec_pgd); -+ xki->page_list[PA_PUD_0] = __ma(kexec_pud0); -+ xki->page_list[PA_PUD_1] = __ma(kexec_pud1); -+ xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); -+ xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); -+ xki->page_list[PA_PTE_0] = __ma(kexec_pte0); -+ xki->page_list[PA_PTE_1] = __ma(kexec_pte1); -+} -+ -+#else /* CONFIG_XEN */ -+ -+#define x__pmd(x) __pmd(x) -+#define x__pud(x) __pud(x) -+#define x__pgd(x) __pgd(x) -+ -+#define x_set_pmd(x, y) set_pmd(x, y) -+#define x_set_pud(x, y) set_pud(x, y) -+#define x_set_pgd(x, y) set_pgd(x, y) -+ -+#define x_pud_clear(x) pud_clear(x) -+#define x_pgd_clear(x) pgd_clear(x) -+ -+#define X__PAGE_KERNEL_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC -+#define X_KERNPG_TABLE _KERNPG_TABLE -+ -+#endif /* CONFIG_XEN */ -+ - static void init_level2_page(pmd_t *level2p, unsigned long addr) - { - unsigned long end_addr; -@@ -31,7 +129,7 @@ static void init_level2_page(pmd_t *leve - addr &= PAGE_MASK; - end_addr = addr + PUD_SIZE; - while (addr < end_addr) { -- set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC)); -+ x_set_pmd(level2p++, x__pmd(addr | X__PAGE_KERNEL_LARGE_EXEC)); - addr += PMD_SIZE; - } - } -@@ -56,12 +154,12 @@ static int init_level3_page(struct kimag - } - level2p = (pmd_t *)page_address(page); - init_level2_page(level2p, addr); -- set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE)); -+ x_set_pud(level3p++, x__pud(__pa(level2p) | X_KERNPG_TABLE)); - addr += PUD_SIZE; - } - /* clear the unused entries */ - while (addr < end_addr) { -- pud_clear(level3p++); -+ x_pud_clear(level3p++); - addr += PUD_SIZE; - } - out: -@@ -92,12 +190,12 @@ static int init_level4_page(struct kimag - if (result) { - goto out; - } -- set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE)); -+ x_set_pgd(level4p++, x__pgd(__pa(level3p) | X_KERNPG_TABLE)); - addr += PGDIR_SIZE; - } - /* clear the unused entries */ - while (addr < end_addr) { -- pgd_clear(level4p++); -+ x_pgd_clear(level4p++); - addr += PGDIR_SIZE; - } - out: -@@ -108,8 +206,14 @@ out: - static int init_pgtable(struct kimage *image, unsigned long start_pgtable) - { - pgd_t *level4p; -+ unsigned long x_end_pfn = end_pfn; -+ -+#ifdef CONFIG_XEN -+ x_end_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); -+#endif -+ - level4p = (pgd_t *)__va(start_pgtable); -- return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); -+ return init_level4_page(image, level4p, 0, x_end_pfn << PAGE_SHIFT); - } - - int machine_kexec_prepare(struct kimage *image) ---- 0009/include/asm-x86_64/kexec.h -+++ work/include/asm-x86_64/kexec.h -@@ -91,6 +91,19 @@ relocate_kernel(unsigned long indirectio - unsigned long page_list, - unsigned long start_address) ATTRIB_NORET; - -+/* Under Xen we need to work with machine addresses. These macros give the -+ * machine address of a certain page to the generic kexec code instead of -+ * the pseudo physical address which would be given by the default macros. -+ */ -+ -+#ifdef CONFIG_XEN -+#define KEXEC_ARCH_HAS_PAGE_MACROS -+#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) -+#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) -+#define kexec_virt_to_phys(addr) virt_to_machine(addr) -+#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) -+#endif -+ - #endif /* __ASSEMBLY__ */ - - #endif /* _X86_64_KEXEC_H */ diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index 1f01b4033f..604aed27e9 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -3,10 +3,8 @@ git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch linux-2.6.19-rc1-kexec-move_segment_code-i386.patch -linux-2.6.19-rc1-kexec-xen-i386.patch git-4bfaaef01a1badb9e8ffb0c0a37cd2379008d21f.patch linux-2.6.19-rc1-kexec-move_segment_code-x86_64.patch -linux-2.6.19-rc1-kexec-xen-x86_64.patch blktap-aio-16_03_06.patch device_bind.patch fix-hz-suspend.patch From 24a9aad534dd075c8ed0619fb2fa02c33b86754a Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 8 Dec 2006 11:47:09 +0000 Subject: [PATCH 266/282] [LINUX] Kexec: add kexec files to sparse tree. Signed-off-by: Ian Campbell --- linux-2.6-xen-sparse/arch/i386/kernel/crash.c | 183 +++ .../arch/i386/kernel/machine_kexec.c | 89 ++ .../arch/x86_64/kernel/crash.c | 186 +++ .../arch/x86_64/kernel/machine_kexec.c | 173 +++ linux-2.6-xen-sparse/include/asm-i386/kexec.h | 103 ++ .../include/asm-x86_64/kexec.h | 96 ++ linux-2.6-xen-sparse/include/linux/kexec.h | 139 +++ linux-2.6-xen-sparse/kernel/kexec.c | 1081 +++++++++++++++++ 8 files changed, 2050 insertions(+) create mode 100644 linux-2.6-xen-sparse/arch/i386/kernel/crash.c create mode 100644 linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c create mode 100644 linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c create mode 100644 linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c create mode 100644 linux-2.6-xen-sparse/include/asm-i386/kexec.h create mode 100644 linux-2.6-xen-sparse/include/asm-x86_64/kexec.h create mode 100644 linux-2.6-xen-sparse/include/linux/kexec.h create mode 100644 linux-2.6-xen-sparse/kernel/kexec.c diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/crash.c b/linux-2.6-xen-sparse/arch/i386/kernel/crash.c new file mode 100644 index 0000000000..d49dbe8dc9 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/i386/kernel/crash.c @@ -0,0 +1,183 @@ +/* + * Architecture specific (i386) functions for kexec based crash dumps. + * + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * + * Copyright (C) IBM Corporation, 2004. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* This keeps a track of which one is crashing cpu. */ +static int crashing_cpu; + +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, + size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) +3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +static void crash_save_this_cpu(struct pt_regs *regs, int cpu) +{ + struct elf_prstatus prstatus; + u32 *buf; + + if ((cpu < 0) || (cpu >= NR_CPUS)) + return; + + /* Using ELF notes here is opportunistic. + * I need a well defined structure format + * for the data I pass, and I need tags + * on the data to indicate what information I have + * squirrelled away. ELF notes happen to provide + * all of that that no need to invent something new. + */ + buf = (u32*)per_cpu_ptr(crash_notes, cpu); + if (!buf) + return; + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + elf_core_copy_regs(&prstatus.pr_reg, regs); + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} + +static void crash_save_self(struct pt_regs *regs) +{ + int cpu; + + cpu = smp_processor_id(); + crash_save_this_cpu(regs, cpu); +} + +#ifdef CONFIG_SMP +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct pt_regs *regs, int cpu) +{ + struct pt_regs fixed_regs; + + /* Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return 1; + local_irq_disable(); + + if (!user_mode(regs)) { + crash_fixup_ss_esp(&fixed_regs, regs); + regs = &fixed_regs; + } + crash_save_this_cpu(regs, cpu); + disable_local_APIC(); + atomic_dec(&waiting_for_crash_ipi); + /* Assume hlt works */ + halt(); + for(;;); + + return 1; +} + +/* + * By using the NMI code instead of a vector we just sneak thru the + * word generator coming out with just what we want. AND it does + * not matter if clustered_apic_mode is set or not. + */ +static void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + +static void nmi_shootdown_cpus(void) +{ + unsigned long msecs; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + /* Would it be better to replace the trap vector here? */ + set_nmi_callback(crash_nmi_callback); + /* Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + + /* Leave the nmi callback set */ + disable_local_APIC(); +} +#else +static void nmi_shootdown_cpus(void) +{ + /* There are no cpus to shootdown */ +} +#endif + +void machine_crash_shutdown(struct pt_regs *regs) +{ + /* This function is only called after the system + * has paniced or is otherwise in a critical state. + * The minimum amount of code to allow a kexec'd kernel + * to run successfully needs to happen here. + * + * In practice this means shooting down the other cpus in + * an SMP system. + */ + /* The kernel is broken so disable interrupts */ + local_irq_disable(); + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = smp_processor_id(); + nmi_shootdown_cpus(); + lapic_shutdown(); +#if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); +#endif + crash_save_self(regs); +} diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c b/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c new file mode 100644 index 0000000000..00e1c189fc --- /dev/null +++ b/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c @@ -0,0 +1,89 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2005 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) +static u32 kexec_pgd[1024] PAGE_ALIGNED; +#ifdef CONFIG_X86_PAE +static u32 kexec_pmd0[1024] PAGE_ALIGNED; +static u32 kexec_pmd1[1024] PAGE_ALIGNED; +#endif +static u32 kexec_pte0[1024] PAGE_ALIGNED; +static u32 kexec_pte1[1024] PAGE_ALIGNED; + +/* + * A architecture hook called to validate the + * proposed image and prepare the control pages + * as needed. The pages for KEXEC_CONTROL_CODE_SIZE + * have been allocated, but the segments have yet + * been copied into the kernel. + * + * Do what every setup is needed on image and the + * reboot code buffer to allow us to avoid allocations + * later. + * + * Currently nothing. + */ +int machine_kexec_prepare(struct kimage *image) +{ + return 0; +} + +/* + * Undo anything leftover by machine_kexec_prepare + * when an image is freed. + */ +void machine_kexec_cleanup(struct kimage *image) +{ +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) +{ + unsigned long page_list[PAGES_NR]; + void *control_page; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + control_page = page_address(image->control_code_page); + memcpy(control_page, relocate_kernel, PAGE_SIZE); + + page_list[PA_CONTROL_PAGE] = __pa(control_page); + page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; + page_list[PA_PGD] = __pa(kexec_pgd); + page_list[VA_PGD] = (unsigned long)kexec_pgd; +#ifdef CONFIG_X86_PAE + page_list[PA_PMD_0] = __pa(kexec_pmd0); + page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; + page_list[PA_PMD_1] = __pa(kexec_pmd1); + page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; +#endif + page_list[PA_PTE_0] = __pa(kexec_pte0); + page_list[VA_PTE_0] = (unsigned long)kexec_pte0; + page_list[PA_PTE_1] = __pa(kexec_pte1); + page_list[VA_PTE_1] = (unsigned long)kexec_pte1; + + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start, cpu_has_pae); +} diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c new file mode 100644 index 0000000000..4e6c3b729e --- /dev/null +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c @@ -0,0 +1,186 @@ +/* + * Architecture specific (x86_64) functions for kexec based crash dumps. + * + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * + * Copyright (C) IBM Corporation, 2004. All rights reserved. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* This keeps a track of which one is crashing cpu. */ +static int crashing_cpu; + +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, + void *data, size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) +3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +static void crash_save_this_cpu(struct pt_regs *regs, int cpu) +{ + struct elf_prstatus prstatus; + u32 *buf; + + if ((cpu < 0) || (cpu >= NR_CPUS)) + return; + + /* Using ELF notes here is opportunistic. + * I need a well defined structure format + * for the data I pass, and I need tags + * on the data to indicate what information I have + * squirrelled away. ELF notes happen to provide + * all of that that no need to invent something new. + */ + + buf = (u32*)per_cpu_ptr(crash_notes, cpu); + + if (!buf) + return; + + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + elf_core_copy_regs(&prstatus.pr_reg, regs); + buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus, + sizeof(prstatus)); + final_note(buf); +} + +static void crash_save_self(struct pt_regs *regs) +{ + int cpu; + + cpu = smp_processor_id(); + crash_save_this_cpu(regs, cpu); +} + +#ifdef CONFIG_SMP +static atomic_t waiting_for_crash_ipi; + +static int crash_nmi_callback(struct pt_regs *regs, int cpu) +{ + /* + * Don't do anything if this handler is invoked on crashing cpu. + * Otherwise, system will completely hang. Crashing cpu can get + * an NMI if system was initially booted with nmi_watchdog parameter. + */ + if (cpu == crashing_cpu) + return 1; + local_irq_disable(); + + crash_save_this_cpu(regs, cpu); + disable_local_APIC(); + atomic_dec(&waiting_for_crash_ipi); + /* Assume hlt works */ + for(;;) + asm("hlt"); + + return 1; +} + +static void smp_send_nmi_allbutself(void) +{ + send_IPI_allbutself(APIC_DM_NMI); +} + +/* + * This code is a best effort heuristic to get the + * other cpus to stop executing. So races with + * cpu hotplug shouldn't matter. + */ + +static void nmi_shootdown_cpus(void) +{ + unsigned long msecs; + + atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); + set_nmi_callback(crash_nmi_callback); + + /* + * Ensure the new callback function is set before sending + * out the NMI + */ + wmb(); + + smp_send_nmi_allbutself(); + + msecs = 1000; /* Wait at most a second for the other cpus to stop */ + while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) { + mdelay(1); + msecs--; + } + /* Leave the nmi callback set */ + disable_local_APIC(); +} +#else +static void nmi_shootdown_cpus(void) +{ + /* There are no cpus to shootdown */ +} +#endif + +void machine_crash_shutdown(struct pt_regs *regs) +{ + /* + * This function is only called after the system + * has paniced or is otherwise in a critical state. + * The minimum amount of code to allow a kexec'd kernel + * to run successfully needs to happen here. + * + * In practice this means shooting down the other cpus in + * an SMP system. + */ + /* The kernel is broken so disable interrupts */ + local_irq_disable(); + + /* Make a note of crashing cpu. Will be used in NMI callback.*/ + crashing_cpu = smp_processor_id(); + nmi_shootdown_cpus(); + + if(cpu_has_apic) + disable_local_APIC(); + +#if defined(CONFIG_X86_IO_APIC) + disable_IO_APIC(); +#endif + + crash_save_self(regs); +} diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c new file mode 100644 index 0000000000..52e5171181 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c @@ -0,0 +1,173 @@ +/* + * machine_kexec.c - handle transition of Linux booting another kernel + * Copyright (C) 2002-2005 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) +static u64 kexec_pgd[512] PAGE_ALIGNED; +static u64 kexec_pud0[512] PAGE_ALIGNED; +static u64 kexec_pmd0[512] PAGE_ALIGNED; +static u64 kexec_pte0[512] PAGE_ALIGNED; +static u64 kexec_pud1[512] PAGE_ALIGNED; +static u64 kexec_pmd1[512] PAGE_ALIGNED; +static u64 kexec_pte1[512] PAGE_ALIGNED; + +static void init_level2_page(pmd_t *level2p, unsigned long addr) +{ + unsigned long end_addr; + + addr &= PAGE_MASK; + end_addr = addr + PUD_SIZE; + while (addr < end_addr) { + set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC)); + addr += PMD_SIZE; + } +} + +static int init_level3_page(struct kimage *image, pud_t *level3p, + unsigned long addr, unsigned long last_addr) +{ + unsigned long end_addr; + int result; + + result = 0; + addr &= PAGE_MASK; + end_addr = addr + PGDIR_SIZE; + while ((addr < last_addr) && (addr < end_addr)) { + struct page *page; + pmd_t *level2p; + + page = kimage_alloc_control_pages(image, 0); + if (!page) { + result = -ENOMEM; + goto out; + } + level2p = (pmd_t *)page_address(page); + init_level2_page(level2p, addr); + set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE)); + addr += PUD_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { + pud_clear(level3p++); + addr += PUD_SIZE; + } +out: + return result; +} + + +static int init_level4_page(struct kimage *image, pgd_t *level4p, + unsigned long addr, unsigned long last_addr) +{ + unsigned long end_addr; + int result; + + result = 0; + addr &= PAGE_MASK; + end_addr = addr + (PTRS_PER_PGD * PGDIR_SIZE); + while ((addr < last_addr) && (addr < end_addr)) { + struct page *page; + pud_t *level3p; + + page = kimage_alloc_control_pages(image, 0); + if (!page) { + result = -ENOMEM; + goto out; + } + level3p = (pud_t *)page_address(page); + result = init_level3_page(image, level3p, addr, last_addr); + if (result) { + goto out; + } + set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE)); + addr += PGDIR_SIZE; + } + /* clear the unused entries */ + while (addr < end_addr) { + pgd_clear(level4p++); + addr += PGDIR_SIZE; + } +out: + return result; +} + + +static int init_pgtable(struct kimage *image, unsigned long start_pgtable) +{ + pgd_t *level4p; + level4p = (pgd_t *)__va(start_pgtable); + return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); +} + +int machine_kexec_prepare(struct kimage *image) +{ + unsigned long start_pgtable; + int result; + + /* Calculate the offsets */ + start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT; + + /* Setup the identity mapped 64bit page table */ + result = init_pgtable(image, start_pgtable); + if (result) + return result; + + return 0; +} + +void machine_kexec_cleanup(struct kimage *image) +{ + return; +} + +/* + * Do not allocate memory (or fail in any way) in machine_kexec(). + * We are past the point of no return, committed to rebooting now. + */ +NORET_TYPE void machine_kexec(struct kimage *image) +{ + unsigned long page_list[PAGES_NR]; + void *control_page; + + /* Interrupts aren't acceptable while we reboot */ + local_irq_disable(); + + control_page = page_address(image->control_code_page) + PAGE_SIZE; + memcpy(control_page, relocate_kernel, PAGE_SIZE); + + page_list[PA_CONTROL_PAGE] = __pa(control_page); + page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; + page_list[PA_PGD] = __pa(kexec_pgd); + page_list[VA_PGD] = (unsigned long)kexec_pgd; + page_list[PA_PUD_0] = __pa(kexec_pud0); + page_list[VA_PUD_0] = (unsigned long)kexec_pud0; + page_list[PA_PMD_0] = __pa(kexec_pmd0); + page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; + page_list[PA_PTE_0] = __pa(kexec_pte0); + page_list[VA_PTE_0] = (unsigned long)kexec_pte0; + page_list[PA_PUD_1] = __pa(kexec_pud1); + page_list[VA_PUD_1] = (unsigned long)kexec_pud1; + page_list[PA_PMD_1] = __pa(kexec_pmd1); + page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; + page_list[PA_PTE_1] = __pa(kexec_pte1); + page_list[VA_PTE_1] = (unsigned long)kexec_pte1; + + page_list[PA_TABLE_PAGE] = + (unsigned long)__pa(page_address(image->control_code_page)); + + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, + image->start); +} diff --git a/linux-2.6-xen-sparse/include/asm-i386/kexec.h b/linux-2.6-xen-sparse/include/asm-i386/kexec.h new file mode 100644 index 0000000000..4dfc9f5ed0 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-i386/kexec.h @@ -0,0 +1,103 @@ +#ifndef _I386_KEXEC_H +#define _I386_KEXEC_H + +#define PA_CONTROL_PAGE 0 +#define VA_CONTROL_PAGE 1 +#define PA_PGD 2 +#define VA_PGD 3 +#define PA_PTE_0 4 +#define VA_PTE_0 5 +#define PA_PTE_1 6 +#define VA_PTE_1 7 +#ifdef CONFIG_X86_PAE +#define PA_PMD_0 8 +#define VA_PMD_0 9 +#define PA_PMD_1 10 +#define VA_PMD_1 11 +#define PAGES_NR 12 +#else +#define PAGES_NR 8 +#endif + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct + * calculation for the amount of memory directly mappable into the + * kernel memory space. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE + +#define KEXEC_CONTROL_CODE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_386 + +#define MAX_NOTE_BYTES 1024 + +/* CPU does not save ss and esp on stack if execution is already + * running in kernel mode at the time of NMI occurrence. This code + * fixes it. + */ +static inline void crash_fixup_ss_esp(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + memcpy(newregs, oldregs, sizeof(*newregs)); + newregs->esp = (unsigned long)&(oldregs->esp); + __asm__ __volatile__( + "xorl %%eax, %%eax\n\t" + "movw %%ss, %%ax\n\t" + :"=a"(newregs->xss)); +} + +/* + * This function is responsible for capturing register states if coming + * via panic otherwise just fix up the ss and esp if coming via kernel + * mode exception. + */ +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + if (oldregs) + crash_fixup_ss_esp(newregs, oldregs); + else { + __asm__ __volatile__("movl %%ebx,%0" : "=m"(newregs->ebx)); + __asm__ __volatile__("movl %%ecx,%0" : "=m"(newregs->ecx)); + __asm__ __volatile__("movl %%edx,%0" : "=m"(newregs->edx)); + __asm__ __volatile__("movl %%esi,%0" : "=m"(newregs->esi)); + __asm__ __volatile__("movl %%edi,%0" : "=m"(newregs->edi)); + __asm__ __volatile__("movl %%ebp,%0" : "=m"(newregs->ebp)); + __asm__ __volatile__("movl %%eax,%0" : "=m"(newregs->eax)); + __asm__ __volatile__("movl %%esp,%0" : "=m"(newregs->esp)); + __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(newregs->xss)); + __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(newregs->xcs)); + __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(newregs->xds)); + __asm__ __volatile__("movw %%es, %%ax;" :"=a"(newregs->xes)); + __asm__ __volatile__("pushfl; popl %0" :"=m"(newregs->eflags)); + + newregs->eip = (unsigned long)current_text_addr(); + } +} +asmlinkage NORET_TYPE void +relocate_kernel(unsigned long indirection_page, + unsigned long control_page, + unsigned long start_address, + unsigned int has_pae) ATTRIB_NORET; + +#endif /* __ASSEMBLY__ */ + +#endif /* _I386_KEXEC_H */ diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h b/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h new file mode 100644 index 0000000000..5fab957e10 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h @@ -0,0 +1,96 @@ +#ifndef _X86_64_KEXEC_H +#define _X86_64_KEXEC_H + +#define PA_CONTROL_PAGE 0 +#define VA_CONTROL_PAGE 1 +#define PA_PGD 2 +#define VA_PGD 3 +#define PA_PUD_0 4 +#define VA_PUD_0 5 +#define PA_PMD_0 6 +#define VA_PMD_0 7 +#define PA_PTE_0 8 +#define VA_PTE_0 9 +#define PA_PUD_1 10 +#define VA_PUD_1 11 +#define PA_PMD_1 12 +#define VA_PMD_1 13 +#define PA_PTE_1 14 +#define VA_PTE_1 15 +#define PA_TABLE_PAGE 16 +#define PAGES_NR 17 + +#ifndef __ASSEMBLY__ + +#include + +#include +#include + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * So far x86_64 is limited to 40 physical address bits. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (0xFFFFFFFFFFUL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL) +/* Maximum address we can use for the control pages */ +#define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL) + +/* Allocate one page for the pdp and the second for the code */ +#define KEXEC_CONTROL_CODE_SIZE (4096UL + 4096UL) + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_X86_64 + +#define MAX_NOTE_BYTES 1024 + +/* + * Saving the registers of the cpu on which panic occured in + * crash_kexec to save a valid sp. The registers of other cpus + * will be saved in machine_crash_shutdown while shooting down them. + */ + +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + if (oldregs) + memcpy(newregs, oldregs, sizeof(*newregs)); + else { + __asm__ __volatile__("movq %%rbx,%0" : "=m"(newregs->rbx)); + __asm__ __volatile__("movq %%rcx,%0" : "=m"(newregs->rcx)); + __asm__ __volatile__("movq %%rdx,%0" : "=m"(newregs->rdx)); + __asm__ __volatile__("movq %%rsi,%0" : "=m"(newregs->rsi)); + __asm__ __volatile__("movq %%rdi,%0" : "=m"(newregs->rdi)); + __asm__ __volatile__("movq %%rbp,%0" : "=m"(newregs->rbp)); + __asm__ __volatile__("movq %%rax,%0" : "=m"(newregs->rax)); + __asm__ __volatile__("movq %%rsp,%0" : "=m"(newregs->rsp)); + __asm__ __volatile__("movq %%r8,%0" : "=m"(newregs->r8)); + __asm__ __volatile__("movq %%r9,%0" : "=m"(newregs->r9)); + __asm__ __volatile__("movq %%r10,%0" : "=m"(newregs->r10)); + __asm__ __volatile__("movq %%r11,%0" : "=m"(newregs->r11)); + __asm__ __volatile__("movq %%r12,%0" : "=m"(newregs->r12)); + __asm__ __volatile__("movq %%r13,%0" : "=m"(newregs->r13)); + __asm__ __volatile__("movq %%r14,%0" : "=m"(newregs->r14)); + __asm__ __volatile__("movq %%r15,%0" : "=m"(newregs->r15)); + __asm__ __volatile__("movl %%ss, %%eax;" :"=a"(newregs->ss)); + __asm__ __volatile__("movl %%cs, %%eax;" :"=a"(newregs->cs)); + __asm__ __volatile__("pushfq; popq %0" :"=m"(newregs->eflags)); + + newregs->rip = (unsigned long)current_text_addr(); + } +} + +NORET_TYPE void +relocate_kernel(unsigned long indirection_page, + unsigned long page_list, + unsigned long start_address) ATTRIB_NORET; + +#endif /* __ASSEMBLY__ */ + +#endif /* _X86_64_KEXEC_H */ diff --git a/linux-2.6-xen-sparse/include/linux/kexec.h b/linux-2.6-xen-sparse/include/linux/kexec.h new file mode 100644 index 0000000000..cfb3410e32 --- /dev/null +++ b/linux-2.6-xen-sparse/include/linux/kexec.h @@ -0,0 +1,139 @@ +#ifndef LINUX_KEXEC_H +#define LINUX_KEXEC_H + +#ifdef CONFIG_KEXEC +#include +#include +#include +#include +#include +#include + +/* Verify architecture specific macros are defined */ + +#ifndef KEXEC_SOURCE_MEMORY_LIMIT +#error KEXEC_SOURCE_MEMORY_LIMIT not defined +#endif + +#ifndef KEXEC_DESTINATION_MEMORY_LIMIT +#error KEXEC_DESTINATION_MEMORY_LIMIT not defined +#endif + +#ifndef KEXEC_CONTROL_MEMORY_LIMIT +#error KEXEC_CONTROL_MEMORY_LIMIT not defined +#endif + +#ifndef KEXEC_CONTROL_CODE_SIZE +#error KEXEC_CONTROL_CODE_SIZE not defined +#endif + +#ifndef KEXEC_ARCH +#error KEXEC_ARCH not defined +#endif + +/* + * This structure is used to hold the arguments that are used when loading + * kernel binaries. + */ + +typedef unsigned long kimage_entry_t; +#define IND_DESTINATION 0x1 +#define IND_INDIRECTION 0x2 +#define IND_DONE 0x4 +#define IND_SOURCE 0x8 + +#define KEXEC_SEGMENT_MAX 16 +struct kexec_segment { + void __user *buf; + size_t bufsz; + unsigned long mem; /* User space sees this as a (void *) ... */ + size_t memsz; +}; + +#ifdef CONFIG_COMPAT +struct compat_kexec_segment { + compat_uptr_t buf; + compat_size_t bufsz; + compat_ulong_t mem; /* User space sees this as a (void *) ... */ + compat_size_t memsz; +}; +#endif + +struct kimage { + kimage_entry_t head; + kimage_entry_t *entry; + kimage_entry_t *last_entry; + + unsigned long destination; + + unsigned long start; + struct page *control_code_page; + + unsigned long nr_segments; + struct kexec_segment segment[KEXEC_SEGMENT_MAX]; + + struct list_head control_pages; + struct list_head dest_pages; + struct list_head unuseable_pages; + + /* Address of next control page to allocate for crash kernels. */ + unsigned long control_page; + + /* Flags to indicate special processing */ + unsigned int type : 1; +#define KEXEC_TYPE_DEFAULT 0 +#define KEXEC_TYPE_CRASH 1 +}; + + + +/* kexec interface functions */ +extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; +extern int machine_kexec_prepare(struct kimage *image); +extern void machine_kexec_cleanup(struct kimage *image); +extern asmlinkage long sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments, + unsigned long flags); +#ifdef CONFIG_COMPAT +extern asmlinkage long compat_sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct compat_kexec_segment __user *segments, + unsigned long flags); +#endif +extern struct page *kimage_alloc_control_pages(struct kimage *image, + unsigned int order); +extern void crash_kexec(struct pt_regs *); +int kexec_should_crash(struct task_struct *); +extern struct kimage *kexec_image; + +#define KEXEC_ON_CRASH 0x00000001 +#define KEXEC_ARCH_MASK 0xffff0000 + +/* These values match the ELF architecture values. + * Unless there is a good reason that should continue to be the case. + */ +#define KEXEC_ARCH_DEFAULT ( 0 << 16) +#define KEXEC_ARCH_386 ( 3 << 16) +#define KEXEC_ARCH_X86_64 (62 << 16) +#define KEXEC_ARCH_PPC (20 << 16) +#define KEXEC_ARCH_PPC64 (21 << 16) +#define KEXEC_ARCH_IA_64 (50 << 16) +#define KEXEC_ARCH_S390 (22 << 16) +#define KEXEC_ARCH_SH (42 << 16) + +#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */ + +/* Location of a reserved region to hold the crash kernel. + */ +extern struct resource crashk_res; +typedef u32 note_buf_t[MAX_NOTE_BYTES/4]; +extern note_buf_t *crash_notes; + +#else /* !CONFIG_KEXEC */ +struct pt_regs; +struct task_struct; +static inline void crash_kexec(struct pt_regs *regs) { } +static inline int kexec_should_crash(struct task_struct *p) { return 0; } +#endif /* CONFIG_KEXEC */ +#endif /* LINUX_KEXEC_H */ diff --git a/linux-2.6-xen-sparse/kernel/kexec.c b/linux-2.6-xen-sparse/kernel/kexec.c new file mode 100644 index 0000000000..bf39d28e4c --- /dev/null +++ b/linux-2.6-xen-sparse/kernel/kexec.c @@ -0,0 +1,1081 @@ +/* + * kexec.c - kexec system call + * Copyright (C) 2002-2004 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Per cpu memory for storing cpu states in case of system crash. */ +note_buf_t* crash_notes; + +/* Location of the reserved area for the crash kernel */ +struct resource crashk_res = { + .name = "Crash kernel", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +int kexec_should_crash(struct task_struct *p) +{ + if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops) + return 1; + return 0; +} + +/* + * When kexec transitions to the new kernel there is a one-to-one + * mapping between physical and virtual addresses. On processors + * where you can disable the MMU this is trivial, and easy. For + * others it is still a simple predictable page table to setup. + * + * In that environment kexec copies the new kernel to its final + * resting place. This means I can only support memory whose + * physical address can fit in an unsigned long. In particular + * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled. + * If the assembly stub has more restrictive requirements + * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be + * defined more restrictively in . + * + * The code for the transition from the current kernel to the + * the new kernel is placed in the control_code_buffer, whose size + * is given by KEXEC_CONTROL_CODE_SIZE. In the best case only a single + * page of memory is necessary, but some architectures require more. + * Because this memory must be identity mapped in the transition from + * virtual to physical addresses it must live in the range + * 0 - TASK_SIZE, as only the user space mappings are arbitrarily + * modifiable. + * + * The assembly stub in the control code buffer is passed a linked list + * of descriptor pages detailing the source pages of the new kernel, + * and the destination addresses of those source pages. As this data + * structure is not used in the context of the current OS, it must + * be self-contained. + * + * The code has been made to work with highmem pages and will use a + * destination page in its final resting place (if it happens + * to allocate it). The end product of this is that most of the + * physical address space, and most of RAM can be used. + * + * Future directions include: + * - allocating a page table with the control code buffer identity + * mapped, to simplify machine_kexec and make kexec_on_panic more + * reliable. + */ + +/* + * KIMAGE_NO_DEST is an impossible destination address..., for + * allocating pages whose destination address we do not care about. + */ +#define KIMAGE_NO_DEST (-1UL) + +static int kimage_is_destination_range(struct kimage *image, + unsigned long start, unsigned long end); +static struct page *kimage_alloc_page(struct kimage *image, + gfp_t gfp_mask, + unsigned long dest); + +static int do_kimage_alloc(struct kimage **rimage, unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments) +{ + size_t segment_bytes; + struct kimage *image; + unsigned long i; + int result; + + /* Allocate a controlling structure */ + result = -ENOMEM; + image = kmalloc(sizeof(*image), GFP_KERNEL); + if (!image) + goto out; + + memset(image, 0, sizeof(*image)); + image->head = 0; + image->entry = &image->head; + image->last_entry = &image->head; + image->control_page = ~0; /* By default this does not apply */ + image->start = entry; + image->type = KEXEC_TYPE_DEFAULT; + + /* Initialize the list of control pages */ + INIT_LIST_HEAD(&image->control_pages); + + /* Initialize the list of destination pages */ + INIT_LIST_HEAD(&image->dest_pages); + + /* Initialize the list of unuseable pages */ + INIT_LIST_HEAD(&image->unuseable_pages); + + /* Read in the segments */ + image->nr_segments = nr_segments; + segment_bytes = nr_segments * sizeof(*segments); + result = copy_from_user(image->segment, segments, segment_bytes); + if (result) + goto out; + + /* + * Verify we have good destination addresses. The caller is + * responsible for making certain we don't attempt to load + * the new image into invalid or reserved areas of RAM. This + * just verifies it is an address we can use. + * + * Since the kernel does everything in page size chunks ensure + * the destination addreses are page aligned. Too many + * special cases crop of when we don't do this. The most + * insidious is getting overlapping destination addresses + * simply because addresses are changed to page size + * granularity. + */ + result = -EADDRNOTAVAIL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK)) + goto out; + if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT) + goto out; + } + + /* Verify our destination addresses do not overlap. + * If we alloed overlapping destination addresses + * through very weird things can happen with no + * easy explanation as one segment stops on another. + */ + result = -EINVAL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + unsigned long j; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + for (j = 0; j < i; j++) { + unsigned long pstart, pend; + pstart = image->segment[j].mem; + pend = pstart + image->segment[j].memsz; + /* Do the segments overlap ? */ + if ((mend > pstart) && (mstart < pend)) + goto out; + } + } + + /* Ensure our buffer sizes are strictly less than + * our memory sizes. This should always be the case, + * and it is easier to check up front than to be surprised + * later on. + */ + result = -EINVAL; + for (i = 0; i < nr_segments; i++) { + if (image->segment[i].bufsz > image->segment[i].memsz) + goto out; + } + + result = 0; +out: + if (result == 0) + *rimage = image; + else + kfree(image); + + return result; + +} + +static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments) +{ + int result; + struct kimage *image; + + /* Allocate and initialize a controlling structure */ + image = NULL; + result = do_kimage_alloc(&image, entry, nr_segments, segments); + if (result) + goto out; + + *rimage = image; + + /* + * Find a location for the control code buffer, and add it + * the vector of segments so that it's pages will also be + * counted as destination pages. + */ + result = -ENOMEM; + image->control_code_page = kimage_alloc_control_pages(image, + get_order(KEXEC_CONTROL_CODE_SIZE)); + if (!image->control_code_page) { + printk(KERN_ERR "Could not allocate control_code_buffer\n"); + goto out; + } + + result = 0; + out: + if (result == 0) + *rimage = image; + else + kfree(image); + + return result; +} + +static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry, + unsigned long nr_segments, + struct kexec_segment __user *segments) +{ + int result; + struct kimage *image; + unsigned long i; + + image = NULL; + /* Verify we have a valid entry point */ + if ((entry < crashk_res.start) || (entry > crashk_res.end)) { + result = -EADDRNOTAVAIL; + goto out; + } + + /* Allocate and initialize a controlling structure */ + result = do_kimage_alloc(&image, entry, nr_segments, segments); + if (result) + goto out; + + /* Enable the special crash kernel control page + * allocation policy. + */ + image->control_page = crashk_res.start; + image->type = KEXEC_TYPE_CRASH; + + /* + * Verify we have good destination addresses. Normally + * the caller is responsible for making certain we don't + * attempt to load the new image into invalid or reserved + * areas of RAM. But crash kernels are preloaded into a + * reserved area of ram. We must ensure the addresses + * are in the reserved area otherwise preloading the + * kernel could corrupt things. + */ + result = -EADDRNOTAVAIL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz - 1; + /* Ensure we are within the crash kernel limits */ + if ((mstart < crashk_res.start) || (mend > crashk_res.end)) + goto out; + } + + /* + * Find a location for the control code buffer, and add + * the vector of segments so that it's pages will also be + * counted as destination pages. + */ + result = -ENOMEM; + image->control_code_page = kimage_alloc_control_pages(image, + get_order(KEXEC_CONTROL_CODE_SIZE)); + if (!image->control_code_page) { + printk(KERN_ERR "Could not allocate control_code_buffer\n"); + goto out; + } + + result = 0; +out: + if (result == 0) + *rimage = image; + else + kfree(image); + + return result; +} + +static int kimage_is_destination_range(struct kimage *image, + unsigned long start, + unsigned long end) +{ + unsigned long i; + + for (i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((end > mstart) && (start < mend)) + return 1; + } + + return 0; +} + +static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order) +{ + struct page *pages; + + pages = alloc_pages(gfp_mask, order); + if (pages) { + unsigned int count, i; + pages->mapping = NULL; + set_page_private(pages, order); + count = 1 << order; + for (i = 0; i < count; i++) + SetPageReserved(pages + i); + } + + return pages; +} + +static void kimage_free_pages(struct page *page) +{ + unsigned int order, count, i; + + order = page_private(page); + count = 1 << order; + for (i = 0; i < count; i++) + ClearPageReserved(page + i); + __free_pages(page, order); +} + +static void kimage_free_page_list(struct list_head *list) +{ + struct list_head *pos, *next; + + list_for_each_safe(pos, next, list) { + struct page *page; + + page = list_entry(pos, struct page, lru); + list_del(&page->lru); + kimage_free_pages(page); + } +} + +static struct page *kimage_alloc_normal_control_pages(struct kimage *image, + unsigned int order) +{ + /* Control pages are special, they are the intermediaries + * that are needed while we copy the rest of the pages + * to their final resting place. As such they must + * not conflict with either the destination addresses + * or memory the kernel is already using. + * + * The only case where we really need more than one of + * these are for architectures where we cannot disable + * the MMU and must instead generate an identity mapped + * page table for all of the memory. + * + * At worst this runs in O(N) of the image size. + */ + struct list_head extra_pages; + struct page *pages; + unsigned int count; + + count = 1 << order; + INIT_LIST_HEAD(&extra_pages); + + /* Loop while I can allocate a page and the page allocated + * is a destination page. + */ + do { + unsigned long pfn, epfn, addr, eaddr; + + pages = kimage_alloc_pages(GFP_KERNEL, order); + if (!pages) + break; + pfn = page_to_pfn(pages); + epfn = pfn + count; + addr = pfn << PAGE_SHIFT; + eaddr = epfn << PAGE_SHIFT; + if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) || + kimage_is_destination_range(image, addr, eaddr)) { + list_add(&pages->lru, &extra_pages); + pages = NULL; + } + } while (!pages); + + if (pages) { + /* Remember the allocated page... */ + list_add(&pages->lru, &image->control_pages); + + /* Because the page is already in it's destination + * location we will never allocate another page at + * that address. Therefore kimage_alloc_pages + * will not return it (again) and we don't need + * to give it an entry in image->segment[]. + */ + } + /* Deal with the destination pages I have inadvertently allocated. + * + * Ideally I would convert multi-page allocations into single + * page allocations, and add everyting to image->dest_pages. + * + * For now it is simpler to just free the pages. + */ + kimage_free_page_list(&extra_pages); + + return pages; +} + +static struct page *kimage_alloc_crash_control_pages(struct kimage *image, + unsigned int order) +{ + /* Control pages are special, they are the intermediaries + * that are needed while we copy the rest of the pages + * to their final resting place. As such they must + * not conflict with either the destination addresses + * or memory the kernel is already using. + * + * Control pages are also the only pags we must allocate + * when loading a crash kernel. All of the other pages + * are specified by the segments and we just memcpy + * into them directly. + * + * The only case where we really need more than one of + * these are for architectures where we cannot disable + * the MMU and must instead generate an identity mapped + * page table for all of the memory. + * + * Given the low demand this implements a very simple + * allocator that finds the first hole of the appropriate + * size in the reserved memory region, and allocates all + * of the memory up to and including the hole. + */ + unsigned long hole_start, hole_end, size; + struct page *pages; + + pages = NULL; + size = (1 << order) << PAGE_SHIFT; + hole_start = (image->control_page + (size - 1)) & ~(size - 1); + hole_end = hole_start + size - 1; + while (hole_end <= crashk_res.end) { + unsigned long i; + + if (hole_end > KEXEC_CONTROL_MEMORY_LIMIT) + break; + if (hole_end > crashk_res.end) + break; + /* See if I overlap any of the segments */ + for (i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz - 1; + if ((hole_end >= mstart) && (hole_start <= mend)) { + /* Advance the hole to the end of the segment */ + hole_start = (mend + (size - 1)) & ~(size - 1); + hole_end = hole_start + size - 1; + break; + } + } + /* If I don't overlap any segments I have found my hole! */ + if (i == image->nr_segments) { + pages = pfn_to_page(hole_start >> PAGE_SHIFT); + break; + } + } + if (pages) + image->control_page = hole_end; + + return pages; +} + + +struct page *kimage_alloc_control_pages(struct kimage *image, + unsigned int order) +{ + struct page *pages = NULL; + + switch (image->type) { + case KEXEC_TYPE_DEFAULT: + pages = kimage_alloc_normal_control_pages(image, order); + break; + case KEXEC_TYPE_CRASH: + pages = kimage_alloc_crash_control_pages(image, order); + break; + } + + return pages; +} + +static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) +{ + if (*image->entry != 0) + image->entry++; + + if (image->entry == image->last_entry) { + kimage_entry_t *ind_page; + struct page *page; + + page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST); + if (!page) + return -ENOMEM; + + ind_page = page_address(page); + *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; + image->entry = ind_page; + image->last_entry = ind_page + + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); + } + *image->entry = entry; + image->entry++; + *image->entry = 0; + + return 0; +} + +static int kimage_set_destination(struct kimage *image, + unsigned long destination) +{ + int result; + + destination &= PAGE_MASK; + result = kimage_add_entry(image, destination | IND_DESTINATION); + if (result == 0) + image->destination = destination; + + return result; +} + + +static int kimage_add_page(struct kimage *image, unsigned long page) +{ + int result; + + page &= PAGE_MASK; + result = kimage_add_entry(image, page | IND_SOURCE); + if (result == 0) + image->destination += PAGE_SIZE; + + return result; +} + + +static void kimage_free_extra_pages(struct kimage *image) +{ + /* Walk through and free any extra destination pages I may have */ + kimage_free_page_list(&image->dest_pages); + + /* Walk through and free any unuseable pages I have cached */ + kimage_free_page_list(&image->unuseable_pages); + +} +static int kimage_terminate(struct kimage *image) +{ + if (*image->entry != 0) + image->entry++; + + *image->entry = IND_DONE; + + return 0; +} + +#define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION)? \ + phys_to_virt((entry & PAGE_MASK)): ptr +1) + +static void kimage_free_entry(kimage_entry_t entry) +{ + struct page *page; + + page = pfn_to_page(entry >> PAGE_SHIFT); + kimage_free_pages(page); +} + +static void kimage_free(struct kimage *image) +{ + kimage_entry_t *ptr, entry; + kimage_entry_t ind = 0; + + if (!image) + return; + + kimage_free_extra_pages(image); + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_INDIRECTION) { + /* Free the previous indirection page */ + if (ind & IND_INDIRECTION) + kimage_free_entry(ind); + /* Save this indirection page until we are + * done with it. + */ + ind = entry; + } + else if (entry & IND_SOURCE) + kimage_free_entry(entry); + } + /* Free the final indirection page */ + if (ind & IND_INDIRECTION) + kimage_free_entry(ind); + + /* Handle any machine specific cleanup */ + machine_kexec_cleanup(image); + + /* Free the kexec control pages... */ + kimage_free_page_list(&image->control_pages); + kfree(image); +} + +static kimage_entry_t *kimage_dst_used(struct kimage *image, + unsigned long page) +{ + kimage_entry_t *ptr, entry; + unsigned long destination = 0; + + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_DESTINATION) + destination = entry & PAGE_MASK; + else if (entry & IND_SOURCE) { + if (page == destination) + return ptr; + destination += PAGE_SIZE; + } + } + + return NULL; +} + +static struct page *kimage_alloc_page(struct kimage *image, + gfp_t gfp_mask, + unsigned long destination) +{ + /* + * Here we implement safeguards to ensure that a source page + * is not copied to its destination page before the data on + * the destination page is no longer useful. + * + * To do this we maintain the invariant that a source page is + * either its own destination page, or it is not a + * destination page at all. + * + * That is slightly stronger than required, but the proof + * that no problems will not occur is trivial, and the + * implementation is simply to verify. + * + * When allocating all pages normally this algorithm will run + * in O(N) time, but in the worst case it will run in O(N^2) + * time. If the runtime is a problem the data structures can + * be fixed. + */ + struct page *page; + unsigned long addr; + + /* + * Walk through the list of destination pages, and see if I + * have a match. + */ + list_for_each_entry(page, &image->dest_pages, lru) { + addr = page_to_pfn(page) << PAGE_SHIFT; + if (addr == destination) { + list_del(&page->lru); + return page; + } + } + page = NULL; + while (1) { + kimage_entry_t *old; + + /* Allocate a page, if we run out of memory give up */ + page = kimage_alloc_pages(gfp_mask, 0); + if (!page) + return NULL; + /* If the page cannot be used file it away */ + if (page_to_pfn(page) > + (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { + list_add(&page->lru, &image->unuseable_pages); + continue; + } + addr = page_to_pfn(page) << PAGE_SHIFT; + + /* If it is the destination page we want use it */ + if (addr == destination) + break; + + /* If the page is not a destination page use it */ + if (!kimage_is_destination_range(image, addr, + addr + PAGE_SIZE)) + break; + + /* + * I know that the page is someones destination page. + * See if there is already a source page for this + * destination page. And if so swap the source pages. + */ + old = kimage_dst_used(image, addr); + if (old) { + /* If so move it */ + unsigned long old_addr; + struct page *old_page; + + old_addr = *old & PAGE_MASK; + old_page = pfn_to_page(old_addr >> PAGE_SHIFT); + copy_highpage(page, old_page); + *old = addr | (*old & ~PAGE_MASK); + + /* The old page I have found cannot be a + * destination page, so return it. + */ + addr = old_addr; + page = old_page; + break; + } + else { + /* Place the page on the destination list I + * will use it later. + */ + list_add(&page->lru, &image->dest_pages); + } + } + + return page; +} + +static int kimage_load_normal_segment(struct kimage *image, + struct kexec_segment *segment) +{ + unsigned long maddr; + unsigned long ubytes, mbytes; + int result; + unsigned char __user *buf; + + result = 0; + buf = segment->buf; + ubytes = segment->bufsz; + mbytes = segment->memsz; + maddr = segment->mem; + + result = kimage_set_destination(image, maddr); + if (result < 0) + goto out; + + while (mbytes) { + struct page *page; + char *ptr; + size_t uchunk, mchunk; + + page = kimage_alloc_page(image, GFP_HIGHUSER, maddr); + if (page == 0) { + result = -ENOMEM; + goto out; + } + result = kimage_add_page(image, page_to_pfn(page) + << PAGE_SHIFT); + if (result < 0) + goto out; + + ptr = kmap(page); + /* Start with a clear page */ + memset(ptr, 0, PAGE_SIZE); + ptr += maddr & ~PAGE_MASK; + mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); + if (mchunk > mbytes) + mchunk = mbytes; + + uchunk = mchunk; + if (uchunk > ubytes) + uchunk = ubytes; + + result = copy_from_user(ptr, buf, uchunk); + kunmap(page); + if (result) { + result = (result < 0) ? result : -EIO; + goto out; + } + ubytes -= uchunk; + maddr += mchunk; + buf += mchunk; + mbytes -= mchunk; + } +out: + return result; +} + +static int kimage_load_crash_segment(struct kimage *image, + struct kexec_segment *segment) +{ + /* For crash dumps kernels we simply copy the data from + * user space to it's destination. + * We do things a page at a time for the sake of kmap. + */ + unsigned long maddr; + unsigned long ubytes, mbytes; + int result; + unsigned char __user *buf; + + result = 0; + buf = segment->buf; + ubytes = segment->bufsz; + mbytes = segment->memsz; + maddr = segment->mem; + while (mbytes) { + struct page *page; + char *ptr; + size_t uchunk, mchunk; + + page = pfn_to_page(maddr >> PAGE_SHIFT); + if (page == 0) { + result = -ENOMEM; + goto out; + } + ptr = kmap(page); + ptr += maddr & ~PAGE_MASK; + mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK); + if (mchunk > mbytes) + mchunk = mbytes; + + uchunk = mchunk; + if (uchunk > ubytes) { + uchunk = ubytes; + /* Zero the trailing part of the page */ + memset(ptr + uchunk, 0, mchunk - uchunk); + } + result = copy_from_user(ptr, buf, uchunk); + kunmap(page); + if (result) { + result = (result < 0) ? result : -EIO; + goto out; + } + ubytes -= uchunk; + maddr += mchunk; + buf += mchunk; + mbytes -= mchunk; + } +out: + return result; +} + +static int kimage_load_segment(struct kimage *image, + struct kexec_segment *segment) +{ + int result = -ENOMEM; + + switch (image->type) { + case KEXEC_TYPE_DEFAULT: + result = kimage_load_normal_segment(image, segment); + break; + case KEXEC_TYPE_CRASH: + result = kimage_load_crash_segment(image, segment); + break; + } + + return result; +} + +/* + * Exec Kernel system call: for obvious reasons only root may call it. + * + * This call breaks up into three pieces. + * - A generic part which loads the new kernel from the current + * address space, and very carefully places the data in the + * allocated pages. + * + * - A generic part that interacts with the kernel and tells all of + * the devices to shut down. Preventing on-going dmas, and placing + * the devices in a consistent state so a later kernel can + * reinitialize them. + * + * - A machine specific part that includes the syscall number + * and the copies the image to it's final destination. And + * jumps into the image at entry. + * + * kexec does not sync, or unmount filesystems so if you need + * that to happen you need to do that yourself. + */ +struct kimage *kexec_image = NULL; +static struct kimage *kexec_crash_image = NULL; +/* + * A home grown binary mutex. + * Nothing can wait so this mutex is safe to use + * in interrupt context :) + */ +static int kexec_lock = 0; + +asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, + struct kexec_segment __user *segments, + unsigned long flags) +{ + struct kimage **dest_image, *image; + int locked; + int result; + + /* We only trust the superuser with rebooting the system. */ + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + /* + * Verify we have a legal set of flags + * This leaves us room for future extensions. + */ + if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK)) + return -EINVAL; + + /* Verify we are on the appropriate architecture */ + if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) && + ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT)) + return -EINVAL; + + /* Put an artificial cap on the number + * of segments passed to kexec_load. + */ + if (nr_segments > KEXEC_SEGMENT_MAX) + return -EINVAL; + + image = NULL; + result = 0; + + /* Because we write directly to the reserved memory + * region when loading crash kernels we need a mutex here to + * prevent multiple crash kernels from attempting to load + * simultaneously, and to prevent a crash kernel from loading + * over the top of a in use crash kernel. + * + * KISS: always take the mutex. + */ + locked = xchg(&kexec_lock, 1); + if (locked) + return -EBUSY; + + dest_image = &kexec_image; + if (flags & KEXEC_ON_CRASH) + dest_image = &kexec_crash_image; + if (nr_segments > 0) { + unsigned long i; + + /* Loading another kernel to reboot into */ + if ((flags & KEXEC_ON_CRASH) == 0) + result = kimage_normal_alloc(&image, entry, + nr_segments, segments); + /* Loading another kernel to switch to if this one crashes */ + else if (flags & KEXEC_ON_CRASH) { + /* Free any current crash dump kernel before + * we corrupt it. + */ + kimage_free(xchg(&kexec_crash_image, NULL)); + result = kimage_crash_alloc(&image, entry, + nr_segments, segments); + } + if (result) + goto out; + + result = machine_kexec_prepare(image); + if (result) + goto out; + + for (i = 0; i < nr_segments; i++) { + result = kimage_load_segment(image, &image->segment[i]); + if (result) + goto out; + } + result = kimage_terminate(image); + if (result) + goto out; + } + /* Install the new kernel, and Uninstall the old */ + image = xchg(dest_image, image); + +out: + xchg(&kexec_lock, 0); /* Release the mutex */ + kimage_free(image); + + return result; +} + +#ifdef CONFIG_COMPAT +asmlinkage long compat_sys_kexec_load(unsigned long entry, + unsigned long nr_segments, + struct compat_kexec_segment __user *segments, + unsigned long flags) +{ + struct compat_kexec_segment in; + struct kexec_segment out, __user *ksegments; + unsigned long i, result; + + /* Don't allow clients that don't understand the native + * architecture to do anything. + */ + if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT) + return -EINVAL; + + if (nr_segments > KEXEC_SEGMENT_MAX) + return -EINVAL; + + ksegments = compat_alloc_user_space(nr_segments * sizeof(out)); + for (i=0; i < nr_segments; i++) { + result = copy_from_user(&in, &segments[i], sizeof(in)); + if (result) + return -EFAULT; + + out.buf = compat_ptr(in.buf); + out.bufsz = in.bufsz; + out.mem = in.mem; + out.memsz = in.memsz; + + result = copy_to_user(&ksegments[i], &out, sizeof(out)); + if (result) + return -EFAULT; + } + + return sys_kexec_load(entry, nr_segments, ksegments, flags); +} +#endif + +void crash_kexec(struct pt_regs *regs) +{ + struct kimage *image; + int locked; + + + /* Take the kexec_lock here to prevent sys_kexec_load + * running on one cpu from replacing the crash kernel + * we are using after a panic on a different cpu. + * + * If the crash kernel was not located in a fixed area + * of memory the xchg(&kexec_crash_image) would be + * sufficient. But since I reuse the memory... + */ + locked = xchg(&kexec_lock, 1); + if (!locked) { + image = xchg(&kexec_crash_image, NULL); + if (image) { + struct pt_regs fixed_regs; + crash_setup_regs(&fixed_regs, regs); + machine_crash_shutdown(&fixed_regs); + machine_kexec(image); + } + xchg(&kexec_lock, 0); + } +} + +static int __init crash_notes_memory_init(void) +{ + /* Allocate memory for saving cpu registers. */ + crash_notes = alloc_percpu(note_buf_t); + if (!crash_notes) { + printk("Kexec: Memory allocation for saving cpu register" + " states failed\n"); + return -ENOMEM; + } + return 0; +} +module_init(crash_notes_memory_init) From 69f0c953b4257eb4f3956b6240278f834b7e8ba1 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 8 Dec 2006 11:47:09 +0000 Subject: [PATCH 267/282] [LINUX] Kexec: Reapply kexec patches to sparse tree. Signed-off-by: Ian Campbell --- linux-2.6-xen-sparse/arch/i386/kernel/crash.c | 4 + .../arch/i386/kernel/machine_kexec.c | 38 ++++++ .../arch/x86_64/kernel/crash.c | 6 +- .../arch/x86_64/kernel/machine_kexec.c | 116 +++++++++++++++++- linux-2.6-xen-sparse/include/asm-i386/kexec.h | 14 +++ .../include/asm-x86_64/kexec.h | 13 ++ linux-2.6-xen-sparse/include/linux/kexec.h | 14 +++ linux-2.6-xen-sparse/kernel/kexec.c | 52 ++++++-- 8 files changed, 238 insertions(+), 19 deletions(-) diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/crash.c b/linux-2.6-xen-sparse/arch/i386/kernel/crash.c index d49dbe8dc9..75aab8ef35 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/crash.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/crash.c @@ -90,6 +90,7 @@ static void crash_save_self(struct pt_regs *regs) crash_save_this_cpu(regs, cpu); } +#ifndef CONFIG_XEN #ifdef CONFIG_SMP static atomic_t waiting_for_crash_ipi; @@ -158,6 +159,7 @@ static void nmi_shootdown_cpus(void) /* There are no cpus to shootdown */ } #endif +#endif /* CONFIG_XEN */ void machine_crash_shutdown(struct pt_regs *regs) { @@ -174,10 +176,12 @@ void machine_crash_shutdown(struct pt_regs *regs) /* Make a note of crashing cpu. Will be used in NMI callback.*/ crashing_cpu = smp_processor_id(); +#ifndef CONFIG_XEN nmi_shootdown_cpus(); lapic_shutdown(); #if defined(CONFIG_X86_IO_APIC) disable_IO_APIC(); #endif +#endif /* CONFIG_XEN */ crash_save_self(regs); } diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c b/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c index 00e1c189fc..f9ebc85481 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c @@ -19,6 +19,10 @@ #include #include +#ifdef CONFIG_XEN +#include +#endif + #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) static u32 kexec_pgd[1024] PAGE_ALIGNED; #ifdef CONFIG_X86_PAE @@ -28,6 +32,40 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED; static u32 kexec_pte0[1024] PAGE_ALIGNED; static u32 kexec_pte1[1024] PAGE_ALIGNED; +#ifdef CONFIG_XEN + +#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) + +#if PAGES_NR > KEXEC_XEN_NO_PAGES +#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break +#endif + +#if PA_CONTROL_PAGE != 0 +#error PA_CONTROL_PAGE is non zero - Xen support will break +#endif + +void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) +{ + void *control_page; + + memset(xki->page_list, 0, sizeof(xki->page_list)); + + control_page = page_address(image->control_code_page); + memcpy(control_page, relocate_kernel, PAGE_SIZE); + + xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); + xki->page_list[PA_PGD] = __ma(kexec_pgd); +#ifdef CONFIG_X86_PAE + xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); + xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); +#endif + xki->page_list[PA_PTE_0] = __ma(kexec_pte0); + xki->page_list[PA_PTE_1] = __ma(kexec_pte1); + +} + +#endif /* CONFIG_XEN */ + /* * A architecture hook called to validate the * proposed image and prepare the control pages diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c index 4e6c3b729e..3263b5942a 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/crash.c @@ -92,6 +92,7 @@ static void crash_save_self(struct pt_regs *regs) crash_save_this_cpu(regs, cpu); } +#ifndef CONFIG_XEN #ifdef CONFIG_SMP static atomic_t waiting_for_crash_ipi; @@ -156,6 +157,7 @@ static void nmi_shootdown_cpus(void) /* There are no cpus to shootdown */ } #endif +#endif /* CONFIG_XEN */ void machine_crash_shutdown(struct pt_regs *regs) { @@ -173,6 +175,8 @@ void machine_crash_shutdown(struct pt_regs *regs) /* Make a note of crashing cpu. Will be used in NMI callback.*/ crashing_cpu = smp_processor_id(); + +#ifndef CONFIG_XEN nmi_shootdown_cpus(); if(cpu_has_apic) @@ -181,6 +185,6 @@ void machine_crash_shutdown(struct pt_regs *regs) #if defined(CONFIG_X86_IO_APIC) disable_IO_APIC(); #endif - +#endif /* CONFIG_XEN */ crash_save_self(regs); } diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c index 52e5171181..f598578b0c 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c @@ -24,6 +24,104 @@ static u64 kexec_pud1[512] PAGE_ALIGNED; static u64 kexec_pmd1[512] PAGE_ALIGNED; static u64 kexec_pte1[512] PAGE_ALIGNED; +#ifdef CONFIG_XEN + +/* In the case of Xen, override hypervisor functions to be able to create + * a regular identity mapping page table... + */ + +#include +#include + +#define x__pmd(x) ((pmd_t) { (x) } ) +#define x__pud(x) ((pud_t) { (x) } ) +#define x__pgd(x) ((pgd_t) { (x) } ) + +#define x_pmd_val(x) ((x).pmd) +#define x_pud_val(x) ((x).pud) +#define x_pgd_val(x) ((x).pgd) + +static inline void x_set_pmd(pmd_t *dst, pmd_t val) +{ + x_pmd_val(*dst) = x_pmd_val(val); +} + +static inline void x_set_pud(pud_t *dst, pud_t val) +{ + x_pud_val(*dst) = phys_to_machine(x_pud_val(val)); +} + +static inline void x_pud_clear (pud_t *pud) +{ + x_pud_val(*pud) = 0; +} + +static inline void x_set_pgd(pgd_t *dst, pgd_t val) +{ + x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val)); +} + +static inline void x_pgd_clear (pgd_t * pgd) +{ + x_pgd_val(*pgd) = 0; +} + +#define X__PAGE_KERNEL_LARGE_EXEC \ + _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE +#define X_KERNPG_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY + +#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT) + +#if PAGES_NR > KEXEC_XEN_NO_PAGES +#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break +#endif + +#if PA_CONTROL_PAGE != 0 +#error PA_CONTROL_PAGE is non zero - Xen support will break +#endif + +void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image) +{ + void *control_page; + void *table_page; + + memset(xki->page_list, 0, sizeof(xki->page_list)); + + control_page = page_address(image->control_code_page) + PAGE_SIZE; + memcpy(control_page, relocate_kernel, PAGE_SIZE); + + table_page = page_address(image->control_code_page); + + xki->page_list[PA_CONTROL_PAGE] = __ma(control_page); + xki->page_list[PA_TABLE_PAGE] = __ma(table_page); + + xki->page_list[PA_PGD] = __ma(kexec_pgd); + xki->page_list[PA_PUD_0] = __ma(kexec_pud0); + xki->page_list[PA_PUD_1] = __ma(kexec_pud1); + xki->page_list[PA_PMD_0] = __ma(kexec_pmd0); + xki->page_list[PA_PMD_1] = __ma(kexec_pmd1); + xki->page_list[PA_PTE_0] = __ma(kexec_pte0); + xki->page_list[PA_PTE_1] = __ma(kexec_pte1); +} + +#else /* CONFIG_XEN */ + +#define x__pmd(x) __pmd(x) +#define x__pud(x) __pud(x) +#define x__pgd(x) __pgd(x) + +#define x_set_pmd(x, y) set_pmd(x, y) +#define x_set_pud(x, y) set_pud(x, y) +#define x_set_pgd(x, y) set_pgd(x, y) + +#define x_pud_clear(x) pud_clear(x) +#define x_pgd_clear(x) pgd_clear(x) + +#define X__PAGE_KERNEL_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC +#define X_KERNPG_TABLE _KERNPG_TABLE + +#endif /* CONFIG_XEN */ + static void init_level2_page(pmd_t *level2p, unsigned long addr) { unsigned long end_addr; @@ -31,7 +129,7 @@ static void init_level2_page(pmd_t *level2p, unsigned long addr) addr &= PAGE_MASK; end_addr = addr + PUD_SIZE; while (addr < end_addr) { - set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC)); + x_set_pmd(level2p++, x__pmd(addr | X__PAGE_KERNEL_LARGE_EXEC)); addr += PMD_SIZE; } } @@ -56,12 +154,12 @@ static int init_level3_page(struct kimage *image, pud_t *level3p, } level2p = (pmd_t *)page_address(page); init_level2_page(level2p, addr); - set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE)); + x_set_pud(level3p++, x__pud(__pa(level2p) | X_KERNPG_TABLE)); addr += PUD_SIZE; } /* clear the unused entries */ while (addr < end_addr) { - pud_clear(level3p++); + x_pud_clear(level3p++); addr += PUD_SIZE; } out: @@ -92,12 +190,12 @@ static int init_level4_page(struct kimage *image, pgd_t *level4p, if (result) { goto out; } - set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE)); + x_set_pgd(level4p++, x__pgd(__pa(level3p) | X_KERNPG_TABLE)); addr += PGDIR_SIZE; } /* clear the unused entries */ while (addr < end_addr) { - pgd_clear(level4p++); + x_pgd_clear(level4p++); addr += PGDIR_SIZE; } out: @@ -108,8 +206,14 @@ out: static int init_pgtable(struct kimage *image, unsigned long start_pgtable) { pgd_t *level4p; + unsigned long x_end_pfn = end_pfn; + +#ifdef CONFIG_XEN + x_end_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL); +#endif + level4p = (pgd_t *)__va(start_pgtable); - return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT); + return init_level4_page(image, level4p, 0, x_end_pfn << PAGE_SHIFT); } int machine_kexec_prepare(struct kimage *image) diff --git a/linux-2.6-xen-sparse/include/asm-i386/kexec.h b/linux-2.6-xen-sparse/include/asm-i386/kexec.h index 4dfc9f5ed0..4610897c78 100644 --- a/linux-2.6-xen-sparse/include/asm-i386/kexec.h +++ b/linux-2.6-xen-sparse/include/asm-i386/kexec.h @@ -98,6 +98,20 @@ relocate_kernel(unsigned long indirection_page, unsigned long start_address, unsigned int has_pae) ATTRIB_NORET; + +/* Under Xen we need to work with machine addresses. These macros give the + * machine address of a certain page to the generic kexec code instead of + * the pseudo physical address which would be given by the default macros. + */ + +#ifdef CONFIG_XEN +#define KEXEC_ARCH_HAS_PAGE_MACROS +#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) +#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) +#define kexec_virt_to_phys(addr) virt_to_machine(addr) +#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) +#endif + #endif /* __ASSEMBLY__ */ #endif /* _I386_KEXEC_H */ diff --git a/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h b/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h index 5fab957e10..3e112d941b 100644 --- a/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h +++ b/linux-2.6-xen-sparse/include/asm-x86_64/kexec.h @@ -91,6 +91,19 @@ relocate_kernel(unsigned long indirection_page, unsigned long page_list, unsigned long start_address) ATTRIB_NORET; +/* Under Xen we need to work with machine addresses. These macros give the + * machine address of a certain page to the generic kexec code instead of + * the pseudo physical address which would be given by the default macros. + */ + +#ifdef CONFIG_XEN +#define KEXEC_ARCH_HAS_PAGE_MACROS +#define kexec_page_to_pfn(page) pfn_to_mfn(page_to_pfn(page)) +#define kexec_pfn_to_page(pfn) pfn_to_page(mfn_to_pfn(pfn)) +#define kexec_virt_to_phys(addr) virt_to_machine(addr) +#define kexec_phys_to_virt(addr) phys_to_virt(machine_to_phys(addr)) +#endif + #endif /* __ASSEMBLY__ */ #endif /* _X86_64_KEXEC_H */ diff --git a/linux-2.6-xen-sparse/include/linux/kexec.h b/linux-2.6-xen-sparse/include/linux/kexec.h index cfb3410e32..b51072d4ed 100644 --- a/linux-2.6-xen-sparse/include/linux/kexec.h +++ b/linux-2.6-xen-sparse/include/linux/kexec.h @@ -31,6 +31,13 @@ #error KEXEC_ARCH not defined #endif +#ifndef KEXEC_ARCH_HAS_PAGE_MACROS +#define kexec_page_to_pfn(page) page_to_pfn(page) +#define kexec_pfn_to_page(pfn) pfn_to_page(pfn) +#define kexec_virt_to_phys(addr) virt_to_phys(addr) +#define kexec_phys_to_virt(addr) phys_to_virt(addr) +#endif + /* * This structure is used to hold the arguments that are used when loading * kernel binaries. @@ -91,6 +98,13 @@ struct kimage { extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET; extern int machine_kexec_prepare(struct kimage *image); extern void machine_kexec_cleanup(struct kimage *image); +#ifdef CONFIG_XEN +extern int xen_machine_kexec_load(struct kimage *image); +extern void xen_machine_kexec_unload(struct kimage *image); +extern NORET_TYPE void xen_machine_kexec(struct kimage *image) ATTRIB_NORET; +extern void xen_machine_kexec_setup_resources(void); +extern void xen_machine_kexec_register_resources(struct resource *res); +#endif extern asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, diff --git a/linux-2.6-xen-sparse/kernel/kexec.c b/linux-2.6-xen-sparse/kernel/kexec.c index bf39d28e4c..1dd4096967 100644 --- a/linux-2.6-xen-sparse/kernel/kexec.c +++ b/linux-2.6-xen-sparse/kernel/kexec.c @@ -403,7 +403,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image, pages = kimage_alloc_pages(GFP_KERNEL, order); if (!pages) break; - pfn = page_to_pfn(pages); + pfn = kexec_page_to_pfn(pages); epfn = pfn + count; addr = pfn << PAGE_SHIFT; eaddr = epfn << PAGE_SHIFT; @@ -437,6 +437,7 @@ static struct page *kimage_alloc_normal_control_pages(struct kimage *image, return pages; } +#ifndef CONFIG_XEN static struct page *kimage_alloc_crash_control_pages(struct kimage *image, unsigned int order) { @@ -490,7 +491,7 @@ static struct page *kimage_alloc_crash_control_pages(struct kimage *image, } /* If I don't overlap any segments I have found my hole! */ if (i == image->nr_segments) { - pages = pfn_to_page(hole_start >> PAGE_SHIFT); + pages = kexec_pfn_to_page(hole_start >> PAGE_SHIFT); break; } } @@ -517,6 +518,13 @@ struct page *kimage_alloc_control_pages(struct kimage *image, return pages; } +#else /* !CONFIG_XEN */ +struct page *kimage_alloc_control_pages(struct kimage *image, + unsigned int order) +{ + return kimage_alloc_normal_control_pages(image, order); +} +#endif static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) { @@ -532,7 +540,7 @@ static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) return -ENOMEM; ind_page = page_address(page); - *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; + *image->entry = kexec_virt_to_phys(ind_page) | IND_INDIRECTION; image->entry = ind_page; image->last_entry = ind_page + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); @@ -593,13 +601,13 @@ static int kimage_terminate(struct kimage *image) #define for_each_kimage_entry(image, ptr, entry) \ for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ ptr = (entry & IND_INDIRECTION)? \ - phys_to_virt((entry & PAGE_MASK)): ptr +1) + kexec_phys_to_virt((entry & PAGE_MASK)): ptr +1) static void kimage_free_entry(kimage_entry_t entry) { struct page *page; - page = pfn_to_page(entry >> PAGE_SHIFT); + page = kexec_pfn_to_page(entry >> PAGE_SHIFT); kimage_free_pages(page); } @@ -611,6 +619,10 @@ static void kimage_free(struct kimage *image) if (!image) return; +#ifdef CONFIG_XEN + xen_machine_kexec_unload(image); +#endif + kimage_free_extra_pages(image); for_each_kimage_entry(image, ptr, entry) { if (entry & IND_INDIRECTION) { @@ -686,7 +698,7 @@ static struct page *kimage_alloc_page(struct kimage *image, * have a match. */ list_for_each_entry(page, &image->dest_pages, lru) { - addr = page_to_pfn(page) << PAGE_SHIFT; + addr = kexec_page_to_pfn(page) << PAGE_SHIFT; if (addr == destination) { list_del(&page->lru); return page; @@ -701,12 +713,12 @@ static struct page *kimage_alloc_page(struct kimage *image, if (!page) return NULL; /* If the page cannot be used file it away */ - if (page_to_pfn(page) > + if (kexec_page_to_pfn(page) > (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { list_add(&page->lru, &image->unuseable_pages); continue; } - addr = page_to_pfn(page) << PAGE_SHIFT; + addr = kexec_page_to_pfn(page) << PAGE_SHIFT; /* If it is the destination page we want use it */ if (addr == destination) @@ -729,7 +741,7 @@ static struct page *kimage_alloc_page(struct kimage *image, struct page *old_page; old_addr = *old & PAGE_MASK; - old_page = pfn_to_page(old_addr >> PAGE_SHIFT); + old_page = kexec_pfn_to_page(old_addr >> PAGE_SHIFT); copy_highpage(page, old_page); *old = addr | (*old & ~PAGE_MASK); @@ -779,7 +791,7 @@ static int kimage_load_normal_segment(struct kimage *image, result = -ENOMEM; goto out; } - result = kimage_add_page(image, page_to_pfn(page) + result = kimage_add_page(image, kexec_page_to_pfn(page) << PAGE_SHIFT); if (result < 0) goto out; @@ -811,6 +823,7 @@ out: return result; } +#ifndef CONFIG_XEN static int kimage_load_crash_segment(struct kimage *image, struct kexec_segment *segment) { @@ -833,7 +846,7 @@ static int kimage_load_crash_segment(struct kimage *image, char *ptr; size_t uchunk, mchunk; - page = pfn_to_page(maddr >> PAGE_SHIFT); + page = kexec_pfn_to_page(maddr >> PAGE_SHIFT); if (page == 0) { result = -ENOMEM; goto out; @@ -881,6 +894,13 @@ static int kimage_load_segment(struct kimage *image, return result; } +#else /* CONFIG_XEN */ +static int kimage_load_segment(struct kimage *image, + struct kexec_segment *segment) +{ + return kimage_load_normal_segment(image, segment); +} +#endif /* * Exec Kernel system call: for obvious reasons only root may call it. @@ -991,6 +1011,11 @@ asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, if (result) goto out; } +#ifdef CONFIG_XEN + result = xen_machine_kexec_load(image); + if (result) + goto out; +#endif /* Install the new kernel, and Uninstall the old */ image = xchg(dest_image, image); @@ -1045,7 +1070,6 @@ void crash_kexec(struct pt_regs *regs) struct kimage *image; int locked; - /* Take the kexec_lock here to prevent sys_kexec_load * running on one cpu from replacing the crash kernel * we are using after a panic on a different cpu. @@ -1061,7 +1085,11 @@ void crash_kexec(struct pt_regs *regs) struct pt_regs fixed_regs; crash_setup_regs(&fixed_regs, regs); machine_crash_shutdown(&fixed_regs); +#ifdef CONFIG_XEN + xen_machine_kexec(image); +#else machine_kexec(image); +#endif } xchg(&kexec_lock, 0); } From c720eb6ab76d4b6699d022182daf014df3507d97 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 8 Dec 2006 11:47:09 +0000 Subject: [PATCH 268/282] [LINUX] Kexec: Remove remainder of kexec-generic.patch Rename xen_machine_kexec() to just machine_kexec() and only compile in the Xen or native version as appropriate. Signed-off-by: Ian Campbell --- .../arch/i386/kernel/machine_kexec.c | 2 ++ .../arch/x86_64/kernel/machine_kexec.c | 2 ++ .../drivers/xen/core/machine_kexec.c | 2 +- linux-2.6-xen-sparse/include/linux/kexec.h | 1 - linux-2.6-xen-sparse/kernel/kexec.c | 4 ---- patches/linux-2.6.16.33/kexec-generic.patch | 15 --------------- patches/linux-2.6.16.33/series | 1 - 7 files changed, 5 insertions(+), 22 deletions(-) delete mode 100644 patches/linux-2.6.16.33/kexec-generic.patch diff --git a/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c b/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c index f9ebc85481..d3979a6531 100644 --- a/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c +++ b/linux-2.6-xen-sparse/arch/i386/kernel/machine_kexec.c @@ -92,6 +92,7 @@ void machine_kexec_cleanup(struct kimage *image) { } +#ifndef CONFIG_XEN /* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. @@ -125,3 +126,4 @@ NORET_TYPE void machine_kexec(struct kimage *image) relocate_kernel((unsigned long)image->head, (unsigned long)page_list, image->start, cpu_has_pae); } +#endif diff --git a/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c b/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c index f598578b0c..f1d9583880 100644 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/machine_kexec.c @@ -237,6 +237,7 @@ void machine_kexec_cleanup(struct kimage *image) return; } +#ifndef CONFIG_XEN /* * Do not allocate memory (or fail in any way) in machine_kexec(). * We are past the point of no return, committed to rebooting now. @@ -275,3 +276,4 @@ NORET_TYPE void machine_kexec(struct kimage *image) relocate_kernel((unsigned long)image->head, (unsigned long)page_list, image->start); } +#endif diff --git a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c index 5e6b58b390..a16e9d9a22 100644 --- a/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c +++ b/linux-2.6-xen-sparse/drivers/xen/core/machine_kexec.c @@ -163,7 +163,7 @@ void xen_machine_kexec_unload(struct kimage *image) * stop all CPUs and kexec. That is it combines machine_shutdown() * and machine_kexec() in Linux kexec terms. */ -NORET_TYPE void xen_machine_kexec(struct kimage *image) +NORET_TYPE void machine_kexec(struct kimage *image) { xen_kexec_exec_t xke; diff --git a/linux-2.6-xen-sparse/include/linux/kexec.h b/linux-2.6-xen-sparse/include/linux/kexec.h index b51072d4ed..8f4fccf63c 100644 --- a/linux-2.6-xen-sparse/include/linux/kexec.h +++ b/linux-2.6-xen-sparse/include/linux/kexec.h @@ -101,7 +101,6 @@ extern void machine_kexec_cleanup(struct kimage *image); #ifdef CONFIG_XEN extern int xen_machine_kexec_load(struct kimage *image); extern void xen_machine_kexec_unload(struct kimage *image); -extern NORET_TYPE void xen_machine_kexec(struct kimage *image) ATTRIB_NORET; extern void xen_machine_kexec_setup_resources(void); extern void xen_machine_kexec_register_resources(struct resource *res); #endif diff --git a/linux-2.6-xen-sparse/kernel/kexec.c b/linux-2.6-xen-sparse/kernel/kexec.c index 1dd4096967..9a1dbb6ae3 100644 --- a/linux-2.6-xen-sparse/kernel/kexec.c +++ b/linux-2.6-xen-sparse/kernel/kexec.c @@ -1085,11 +1085,7 @@ void crash_kexec(struct pt_regs *regs) struct pt_regs fixed_regs; crash_setup_regs(&fixed_regs, regs); machine_crash_shutdown(&fixed_regs); -#ifdef CONFIG_XEN - xen_machine_kexec(image); -#else machine_kexec(image); -#endif } xchg(&kexec_lock, 0); } diff --git a/patches/linux-2.6.16.33/kexec-generic.patch b/patches/linux-2.6.16.33/kexec-generic.patch deleted file mode 100644 index a85d546e4d..0000000000 --- a/patches/linux-2.6.16.33/kexec-generic.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- 0002/kernel/sys.c -+++ work/kernel/sys.c -@@ -435,8 +435,12 @@ void kernel_kexec(void) - kernel_restart_prepare(NULL); - printk(KERN_EMERG "Starting new kernel\n"); - machine_shutdown(); -+#ifdef CONFIG_XEN -+ xen_machine_kexec(image); -+#else - machine_kexec(image); - #endif -+#endif - } - EXPORT_SYMBOL_GPL(kernel_kexec); - diff --git a/patches/linux-2.6.16.33/series b/patches/linux-2.6.16.33/series index 604aed27e9..28fabf00ff 100644 --- a/patches/linux-2.6.16.33/series +++ b/patches/linux-2.6.16.33/series @@ -1,4 +1,3 @@ -kexec-generic.patch git-2efe55a9cec8418f0e0cde3dc3787a42fddc4411.patch git-2a8a3d5b65e86ec1dfef7d268c64a909eab94af7.patch git-3566561bfadffcb5dbc85d576be80c0dbf2cccc9.patch From b65f717688423c3b3f770d38d63ad681a53121c4 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 11:57:06 +0000 Subject: [PATCH 269/282] [LIBXC] Clean up use of sterror(). Define a thread-safe version which uses strerror_r(), and tries to cope with the POSIX and GNU versions of that function. Signed-off-by: Keir Fraser --- tools/libxc/ia64/xc_ia64_linux_save.c | 2 +- tools/libxc/xc_core.c | 4 ++-- tools/libxc/xc_linux_build.c | 4 ++-- tools/libxc/xc_private.c | 13 +++++++++++++ tools/libxc/xc_private.h | 3 ++- 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/libxc/ia64/xc_ia64_linux_save.c b/tools/libxc/ia64/xc_ia64_linux_save.c index 42ec21c802..d98725445a 100644 --- a/tools/libxc/ia64/xc_ia64_linux_save.c +++ b/tools/libxc/ia64/xc_ia64_linux_save.c @@ -353,7 +353,7 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, It will be remarked dirty. FIXME: to be tracked. */ fprintf(stderr, "cannot map page %lx: %s\n", - page_array[N], strerror (errno)); + page_array[N], safe_strerror(errno)); continue; } diff --git a/tools/libxc/xc_core.c b/tools/libxc/xc_core.c index 550d5691e1..035bf301e5 100644 --- a/tools/libxc/xc_core.c +++ b/tools/libxc/xc_core.c @@ -140,7 +140,7 @@ static int local_file_dump(void *args, char *buffer, unsigned int length) bytes = write(da->fd, &buffer[offset], length-offset); if ( bytes <= 0 ) { - PERROR("Failed to write buffer: %s", strerror(errno)); + PERROR("Failed to write buffer"); return -errno; } } @@ -158,7 +158,7 @@ xc_domain_dumpcore(int xc_handle, if ( (da.fd = open(corename, O_CREAT|O_RDWR, S_IWUSR|S_IRUSR)) < 0 ) { - PERROR("Could not open corefile %s: %s", corename, strerror(errno)); + PERROR("Could not open corefile %s", corename); return -errno; } diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index edf95c0fc0..a2b5274083 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -593,8 +593,8 @@ static int setup_guest(int xc_handle, /* shared_info page starts its life empty. */ shared_info = xc_map_foreign_range( xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame); - printf("shared_info = %p, err=%s frame=%lx\n", - shared_info, strerror (errno), shared_info_frame); + printf("shared_info = %p frame=%lx\n", + shared_info, shared_info_frame); //memset(shared_info, 0, PAGE_SIZE); /* Mask all upcalls... */ for ( i = 0; i < MAX_VIRT_CPUS; i++ ) diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index 3ff0b791d0..ed76cf003c 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -483,6 +483,19 @@ unsigned long xc_make_page_below_4G( return new_mfn; } +char *safe_strerror(int errcode) +{ + static __thread char errbuf[32]; +#ifdef __GLIBC__ + /* Broken GNU definition of strerror_r may not use our supplied buffer. */ + return strerror_r(errcode, errbuf, sizeof(errbuf)); +#else + /* Assume we have the POSIX definition of strerror_r. */ + strerror_r(errcode, errbuf, sizeof(errbuf)); + return errbuf; +#endif +} + /* * Local variables: * mode: C diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h index f087e7de69..6dfbdead7a 100644 --- a/tools/libxc/xc_private.h +++ b/tools/libxc/xc_private.h @@ -59,11 +59,12 @@ #define PPRINTF(_f, _a...) #endif +char *safe_strerror(int errcode); void xc_set_error(int code, const char *fmt, ...); #define ERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m , ## _a ) #define PERROR(_m, _a...) xc_set_error(XC_INTERNAL_ERROR, _m " (%d = %s)", \ - ## _a , errno, strerror(errno)) + ## _a , errno, safe_strerror(errno)) int lock_pages(void *addr, size_t len); void unlock_pages(void *addr, size_t len); From 781b258bf0322191c1d38fa07bc9e2ef945bd51e Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 8 Dec 2006 13:28:22 +0000 Subject: [PATCH 270/282] [XEND] Make sure UUID is in the right format. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 9896254f32..af2971a870 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -390,11 +390,16 @@ class XendConfig(dict): if self.get('vcpus_number') != None: self['vcpu_avail'] = (1 << self['vcpus_number']) - 1 + def _uuid_sanity_check(self): + """Make sure UUID is in proper string format with hyphens.""" + self['uuid'] = uuid.toString(uuid.fromString(self['uuid'])) + def validate(self): self._memory_sanity_check() self._actions_sanity_check() self._builder_sanity_check() self._vcpus_sanity_check() + self._uuid_sanity_check() def _dominfo_to_xapi(self, dominfo): self['domid'] = dominfo['domid'] From e2bfc5ae076d24bf75584028b1d3026ffd8f4d5f Mon Sep 17 00:00:00 2001 From: Alastair Tse Date: Fri, 8 Dec 2006 13:31:21 +0000 Subject: [PATCH 271/282] [XEND] Keep vif IP addresses as space separated string. They were inconsistently represented as strings or lists making it difficult to know the type of the IP parameter for vifs. Since both xm and DevController represents these as space separated strings, that is what it will be stored as. Signed-off-by: Alastair Tse --- tools/python/xen/xend/XendConfig.py | 13 ------------- tools/python/xen/xend/server/netif.py | 4 ++-- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index af2971a870..804a50209c 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -922,24 +922,11 @@ class XendConfig(dict): except ValueError: pass # SXP has no options for this device - - # Special handling for certain device parameters. - - def _get_config_ipaddr(cfg): - val = [] - for ipaddr in sxp.children(cfg, elt='ip'): - val.append(sxp.child0(ipaddr)) - return val - - if dev_type == 'vif' and 'ip' in dev_info: - dev_info['ip'] = _get_config_ipaddr(config) - if dev_type == 'vbd': if dev_info.get('dev', '').startswith('ioemu:'): dev_info['driver'] = 'ioemu' else: dev_info['driver'] = 'paravirtualised' - # create uuid if it doesn't exist dev_uuid = dev_info.get('uuid', uuid.createString()) diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py index a20929a0d9..8b0a2ce66c 100644 --- a/tools/python/xen/xend/server/netif.py +++ b/tools/python/xen/xend/server/netif.py @@ -164,7 +164,7 @@ class NetifController(DevController): front = { 'handle' : "%i" % devid, 'mac' : mac } if ipaddr: - back['ip'] = ' '.join(ipaddr) + back['ip'] = ipaddr if bridge: back['bridge'] = bridge if vifname: @@ -189,7 +189,7 @@ class NetifController(DevController): network_script_dir = xroot.network_script_dir + os.sep result['script'] = script.replace(network_script_dir, "") if ip: - result['ip'] = ip.split(" ") + result['ip'] = ip if bridge: result['bridge'] = bridge if mac: From 9eafa32f4860b2634f0fac37f2987744f58bf299 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Fri, 8 Dec 2006 15:59:30 +0000 Subject: [PATCH 272/282] [LIBXC] Make strerror() thread-safe by protecting it with a mutex. Using strerror_r() is made difficult by the different GNU definition, and different distros variously choose the POSIX or GNU prototype. Signed-off-by: Keir Fraser --- tools/libxc/Makefile | 4 ++-- tools/libxc/xc_private.c | 22 ++++++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 129b867ff6..f92cde836d 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -119,7 +119,7 @@ libxenctrl.so.$(MAJOR): libxenctrl.so.$(MAJOR).$(MINOR) ln -sf $< $@ libxenctrl.so.$(MAJOR).$(MINOR): $(CTRL_PIC_OBJS) - $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenctrl.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $^ -lpthread # libxenguest @@ -132,7 +132,7 @@ libxenguest.so.$(MAJOR): libxenguest.so.$(MAJOR).$(MINOR) ln -sf $< $@ libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so - $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz -lxenctrl + $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz -lxenctrl -lpthread -include $(DEPS) diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index ed76cf003c..82e190989c 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -7,8 +7,8 @@ #include #include "xc_private.h" #include "xg_private.h" - #include +#include static __thread xc_error last_error = { XC_ERROR_NONE, ""}; #if DEBUG @@ -486,14 +486,20 @@ unsigned long xc_make_page_below_4G( char *safe_strerror(int errcode) { static __thread char errbuf[32]; -#ifdef __GLIBC__ - /* Broken GNU definition of strerror_r may not use our supplied buffer. */ - return strerror_r(errcode, errbuf, sizeof(errbuf)); -#else - /* Assume we have the POSIX definition of strerror_r. */ - strerror_r(errcode, errbuf, sizeof(errbuf)); + static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + char *strerror_str; + + /* + * Thread-unsafe strerror() is protected by a local mutex. We copy + * the string to a thread-private buffer before releasing the mutex. + */ + pthread_mutex_lock(&mutex); + strerror_str = strerror(errcode); + strncpy(errbuf, strerror_str, sizeof(errbuf)); + errbuf[sizeof(errbuf)-1] = '\0'; + pthread_mutex_unlock(&mutex); + return errbuf; -#endif } /* From 1dd304690d3a7505fd4987b863dbe7fe02bf5304 Mon Sep 17 00:00:00 2001 From: "john.levon@sun.com" Date: Fri, 8 Dec 2006 07:22:21 -0800 Subject: [PATCH 273/282] xm block-attach can take an optional 5th argument, show it in the help. Signed-off-by: John Levon --- tools/python/xen/xm/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index dff8253639..779b5280b8 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -138,9 +138,9 @@ SUBCOMMAND_HELP = { # device commands - 'block-attach' : (' ', + 'block-attach' : (' [BackDomain]', 'Create a new virtual block device.'), - 'block-configure': (' [BackDomId]', + 'block-configure': (' [BackDomain]', 'Change block device configuration'), 'block-detach' : (' ', 'Destroy a domain\'s virtual block device.'), From 4f4e5dd93dd1ca43d8e0eaef7bb620761b88b171 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Fri, 8 Dec 2006 09:32:15 -0700 Subject: [PATCH 274/282] [IA64] change XEN_DOMCTL_getmemlist to return gmfn instead of mfn This patch tries to get 'xm dump-core' work on ia64 again. With this patch, 'xm dump-core' results in creating core-dump file as before with a slight format changes. (machine address array -> pseudo physicall address array) However xm dump-core has been broken on ia64 since XEN_DOMCTL_getmemlist/ia64 is differenct from x86's. This patch does NOT fix it. Signed-off-by: Isaku Yamahata --- xen/arch/ia64/xen/dom0_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index 472f03dc54..e0aaff58d6 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -55,7 +55,7 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) pte = (pte_t *)lookup_noalloc_domain_pte(d, (start_page + i) << PAGE_SHIFT); if (pte && pte_present(*pte)) - mfn = pte_pfn(*pte); + mfn = start_page + i; else mfn = INVALID_MFN; From 2802359071e3d0924d61aef7eb89c43e3ff95c79 Mon Sep 17 00:00:00 2001 From: Christian Limpach Date: Fri, 8 Dec 2006 18:31:01 +0000 Subject: [PATCH 275/282] [qemu patches] Update patches upto changeset 12756:1d32fb45e0. Signed-off-by: Christian Limpach --- tools/ioemu/patches/acpi-support | 69 +- tools/ioemu/patches/acpi-timer-support | 11 +- tools/ioemu/patches/domain-destroy | 18 +- tools/ioemu/patches/domain-reset | 14 +- tools/ioemu/patches/domain-timeoffset | 20 +- tools/ioemu/patches/fix-interrupt-routing | 459 +++++++ tools/ioemu/patches/hypervisor-pit | 14 +- tools/ioemu/patches/hypervisor-rtc | 16 +- tools/ioemu/patches/ide-error-reporting | 110 ++ tools/ioemu/patches/ioemu-ia64 | 95 +- .../patches/limit-fdc-sector-size-to-16K | 32 + tools/ioemu/patches/ne2000-bounds-checks | 113 ++ tools/ioemu/patches/nodelay-serial-over-tcp | 29 + tools/ioemu/patches/qemu-bootorder | 20 +- tools/ioemu/patches/qemu-daemonize | 6 +- tools/ioemu/patches/qemu-dm | 38 +- tools/ioemu/patches/qemu-no-apic | 10 +- tools/ioemu/patches/qemu-pci | 30 +- tools/ioemu/patches/qemu-serial-fixes | 133 ++ tools/ioemu/patches/qemu-target-i386-dm | 278 ++-- tools/ioemu/patches/remove-pci-bridge-setup | 289 ++++ tools/ioemu/patches/rtl8139-bound-chaining | 36 + tools/ioemu/patches/series | 14 + tools/ioemu/patches/shared-vram | 42 +- tools/ioemu/patches/tpm-tis-device | 1182 +++++++++++++++++ tools/ioemu/patches/usb-uhci-buffer-size | 25 + tools/ioemu/patches/vnc-access-monitor-vt | 6 +- tools/ioemu/patches/vnc-backoff-screen-scan | 28 +- tools/ioemu/patches/vnc-display-find-unused | 26 +- tools/ioemu/patches/vnc-fixes | 54 +- tools/ioemu/patches/vnc-japan-keymap | 39 + .../patches/vnc-listen-specific-interface | 24 +- .../patches/vnc-monitor-shift-key-processing | 60 + tools/ioemu/patches/vnc-numpad-handling | 236 ++++ tools/ioemu/patches/vnc-password | 81 +- tools/ioemu/patches/vnc-protocol-fixes | 10 +- tools/ioemu/patches/vnc-start-vncviewer | 20 +- tools/ioemu/patches/vnc-title-domain-name | 8 +- tools/ioemu/patches/xen-build | 24 +- tools/ioemu/patches/xen-mm | 28 +- tools/ioemu/patches/xen-platform-device | 16 +- .../ioemu/patches/xen-support-buffered-ioreqs | 39 +- .../patches/xenstore-block-device-config | 54 +- .../patches/xenstore-device-info-functions | 190 +++ tools/ioemu/patches/xenstore-write-vnc-port | 14 +- 45 files changed, 3501 insertions(+), 559 deletions(-) create mode 100644 tools/ioemu/patches/fix-interrupt-routing create mode 100644 tools/ioemu/patches/ide-error-reporting create mode 100644 tools/ioemu/patches/limit-fdc-sector-size-to-16K create mode 100644 tools/ioemu/patches/ne2000-bounds-checks create mode 100644 tools/ioemu/patches/nodelay-serial-over-tcp create mode 100644 tools/ioemu/patches/qemu-serial-fixes create mode 100644 tools/ioemu/patches/remove-pci-bridge-setup create mode 100644 tools/ioemu/patches/rtl8139-bound-chaining create mode 100644 tools/ioemu/patches/tpm-tis-device create mode 100644 tools/ioemu/patches/usb-uhci-buffer-size create mode 100644 tools/ioemu/patches/vnc-japan-keymap create mode 100644 tools/ioemu/patches/vnc-monitor-shift-key-processing create mode 100644 tools/ioemu/patches/vnc-numpad-handling create mode 100644 tools/ioemu/patches/xenstore-device-info-functions diff --git a/tools/ioemu/patches/acpi-support b/tools/ioemu/patches/acpi-support index 9baa69fb3b..93f67261c1 100644 --- a/tools/ioemu/patches/acpi-support +++ b/tools/ioemu/patches/acpi-support @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-17 19:49:50.228216099 +0100 -+++ ioemu/Makefile.target 2006-08-17 19:50:02.405870095 +0100 -@@ -357,6 +357,7 @@ +--- ioemu.orig/Makefile.target 2006-12-08 02:00:40.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 02:00:40.000000000 +0000 +@@ -358,6 +358,7 @@ VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o VL_OBJS+= usb-uhci.o @@ -12,8 +12,8 @@ Index: ioemu/Makefile.target ifeq ($(TARGET_BASE_ARCH), ppc) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-17 19:49:59.312212039 +0100 -+++ ioemu/hw/pc.c 2006-08-17 19:50:02.406869984 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 02:00:40.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 02:00:40.000000000 +0000 @@ -874,13 +874,19 @@ cmos_init(ram_size, boot_device, bs_table, timeoffset); @@ -49,8 +49,8 @@ Index: ioemu/hw/pc.c Index: ioemu/hw/piix4acpi.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/hw/piix4acpi.c 2006-08-17 19:50:02.407869874 +0100 -@@ -0,0 +1,388 @@ ++++ ioemu/hw/piix4acpi.c 2006-12-08 02:00:40.000000000 +0000 +@@ -0,0 +1,396 @@ +/* + * PIIX4 ACPI controller emulation + * @@ -434,15 +434,23 @@ Index: ioemu/hw/piix4acpi.c + pci_conf[0x0e] = 0x00; + pci_conf[0x3d] = 0x01; /* Hardwired to PIRQA is used */ + -+ pci_register_io_region((PCIDevice *)d, 4, 0x10, -+ PCI_ADDRESS_SPACE_IO, acpi_map); + -+ acpi_reset (d); ++ /* PMBA POWER MANAGEMENT BASE ADDRESS, hardcoded to 0x1f40 ++ * to make shutdown work for IPF, due to IPF Guest Firmware ++ * will enumerate pci devices. ++ * ++ * TODO: if Guest Firmware or Guest OS will change this PMBA, ++ * More logic will be added. ++ */ ++ pci_conf[0x40] = 0x41; /* Special device-specific BAR at 0x40 */ ++ pci_conf[0x41] = 0x1f; ++ acpi_map(d, 0, 0x1f40, 0x10, PCI_ADDRESS_SPACE_IO); ++ acpi_reset(d); +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-17 19:49:59.315211708 +0100 -+++ ioemu/vl.c 2006-08-17 19:50:02.410869542 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:00:40.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:00:40.000000000 +0000 @@ -156,7 +156,7 @@ #else #define MAX_CPUS 1 @@ -476,7 +484,7 @@ Index: ioemu/vl.c { NULL }, }; -@@ -6256,6 +6259,9 @@ +@@ -6240,6 +6243,9 @@ case QEMU_OPTION_timeoffset: timeoffset = strtol(optarg, NULL, 0); break; @@ -488,8 +496,8 @@ Index: ioemu/vl.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-17 19:49:59.316211597 +0100 -+++ ioemu/vl.h 2006-08-17 19:50:02.411869432 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:00:40.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:00:40.000000000 +0000 @@ -168,6 +168,7 @@ extern int kqemu_allowed; extern int win2k_install_hack; @@ -510,8 +518,8 @@ Index: ioemu/vl.h extern QEMUMachine isapc_machine; Index: ioemu/hw/piix_pci.c =================================================================== ---- ioemu.orig/hw/piix_pci.c 2006-08-17 19:38:05.806252180 +0100 -+++ ioemu/hw/piix_pci.c 2006-08-17 19:50:02.411869432 +0100 +--- ioemu.orig/hw/piix_pci.c 2006-12-08 02:00:39.000000000 +0000 ++++ ioemu/hw/piix_pci.c 2006-12-08 02:00:40.000000000 +0000 @@ -241,7 +241,7 @@ static uint32_t pci_bios_io_addr; static uint32_t pci_bios_mem_addr; @@ -521,33 +529,22 @@ Index: ioemu/hw/piix_pci.c static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) { -@@ -336,6 +336,14 @@ +@@ -336,6 +336,18 @@ pci_set_io_region_addr(d, 3, 0x374); } break; + case 0x0680: + if (vendor_id == 0x8086 && device_id == 0x7113) { -+ /* PIIX4 ACPI PM */ -+ pci_config_writew(d, 0x20, 0x0000); /* NO smb bus IO enable in PIIX4 */ ++ /* ++ * PIIX4 ACPI PM. ++ * Special device with special PCI config space. No ordinary BARs. ++ */ ++ pci_config_writew(d, 0x20, 0x0000); // No smb bus IO enable + pci_config_writew(d, 0x22, 0x0000); -+ goto default_map; ++ pci_config_writew(d, 0x3c, 0x0009); // Hardcoded IRQ9 ++ pci_config_writew(d, 0x3d, 0x0001); + } + break; case 0x0300: if (vendor_id != 0x1234) goto default_map; -@@ -386,6 +394,14 @@ - pic_irq = pci_irqs[pin]; - pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); - } -+ -+ if (class== 0x0680&& vendor_id == 0x8086 && device_id == 0x7113) { -+ // PIIX4 ACPI PM -+ pci_config_writew(d, 0x20, 0x0000); // NO smb bus IO enable in PIIX4 -+ pci_config_writew(d, 0x22, 0x0000); -+ pci_config_writew(d, 0x3c, 0x0009); // Hardcodeed IRQ9 -+ pci_config_writew(d, 0x3d, 0x0001); -+ } - } - - /* diff --git a/tools/ioemu/patches/acpi-timer-support b/tools/ioemu/patches/acpi-timer-support index 74863b1a39..2698827caa 100644 --- a/tools/ioemu/patches/acpi-timer-support +++ b/tools/ioemu/patches/acpi-timer-support @@ -1,7 +1,7 @@ Index: ioemu/hw/piix4acpi.c =================================================================== ---- ioemu.orig/hw/piix4acpi.c 2006-08-17 19:50:02.407869874 +0100 -+++ ioemu/hw/piix4acpi.c 2006-08-17 19:50:05.060576667 +0100 +--- ioemu.orig/hw/piix4acpi.c 2006-12-08 01:35:52.000000000 +0000 ++++ ioemu/hw/piix4acpi.c 2006-12-08 01:35:59.000000000 +0000 @@ -24,31 +24,30 @@ */ @@ -186,10 +186,3 @@ Index: ioemu/hw/piix4acpi.c /* PIIX4 acpi pci configuration space, func 2 */ void pci_piix4_acpi_init(PCIBus *bus, int devfn) -@@ -384,5 +383,5 @@ - pci_register_io_region((PCIDevice *)d, 4, 0x10, - PCI_ADDRESS_SPACE_IO, acpi_map); - -- acpi_reset (d); -+ acpi_reset(d); - } diff --git a/tools/ioemu/patches/domain-destroy b/tools/ioemu/patches/domain-destroy index be630fd895..998325e9fe 100644 --- a/tools/ioemu/patches/domain-destroy +++ b/tools/ioemu/patches/domain-destroy @@ -1,7 +1,7 @@ Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-08-17 19:37:36.489509621 +0100 -+++ ioemu/monitor.c 2006-08-17 19:49:44.491850141 +0100 +--- ioemu.orig/monitor.c 2006-12-08 01:26:07.000000000 +0000 ++++ ioemu/monitor.c 2006-12-08 01:26:08.000000000 +0000 @@ -308,6 +308,7 @@ static void do_quit(void) @@ -12,11 +12,11 @@ Index: ioemu/monitor.c Index: ioemu/target-i386-dm/helper2.c =================================================================== ---- ioemu.orig/target-i386-dm/helper2.c 2006-08-17 19:49:40.116333768 +0100 -+++ ioemu/target-i386-dm/helper2.c 2006-08-17 19:49:44.491850141 +0100 -@@ -488,5 +488,25 @@ - xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); - } +--- ioemu.orig/target-i386-dm/helper2.c 2006-12-08 01:26:08.000000000 +0000 ++++ ioemu/target-i386-dm/helper2.c 2006-12-08 01:26:08.000000000 +0000 +@@ -507,5 +507,25 @@ + /* Wait up to 10 msec. */ + main_loop_wait(10); } + destroy_hvm_domain(); return 0; @@ -42,8 +42,8 @@ Index: ioemu/target-i386-dm/helper2.c +} Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-17 19:49:40.120333326 +0100 -+++ ioemu/vl.h 2006-08-17 19:49:44.492850031 +0100 +--- ioemu.orig/vl.h 2006-12-08 01:26:08.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 01:26:08.000000000 +0000 @@ -1190,4 +1190,7 @@ void kqemu_record_dump(void); diff --git a/tools/ioemu/patches/domain-reset b/tools/ioemu/patches/domain-reset index 838e345d2a..c754cfaf78 100644 --- a/tools/ioemu/patches/domain-reset +++ b/tools/ioemu/patches/domain-reset @@ -1,7 +1,7 @@ Index: ioemu/target-i386-dm/helper2.c =================================================================== ---- ioemu.orig/target-i386-dm/helper2.c 2006-08-17 19:37:36.530505066 +0100 -+++ ioemu/target-i386-dm/helper2.c 2006-08-17 19:49:40.116333768 +0100 +--- ioemu.orig/target-i386-dm/helper2.c 2006-12-08 01:26:06.000000000 +0000 ++++ ioemu/target-i386-dm/helper2.c 2006-12-08 01:26:08.000000000 +0000 @@ -127,6 +127,25 @@ /* called from main_cpu_reset */ void cpu_reset(CPUX86State *env) @@ -28,7 +28,7 @@ Index: ioemu/target-i386-dm/helper2.c } void cpu_x86_close(CPUX86State *env) -@@ -455,6 +474,10 @@ +@@ -479,6 +498,10 @@ if (vm_running) { if (shutdown_requested) break; @@ -41,8 +41,8 @@ Index: ioemu/target-i386-dm/helper2.c /* Wait up to 10 msec. */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-17 19:49:39.442408257 +0100 -+++ ioemu/vl.c 2006-08-17 19:49:40.119333436 +0100 +--- ioemu.orig/vl.c 2006-12-08 01:26:08.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 01:26:08.000000000 +0000 @@ -4948,7 +4948,7 @@ } QEMUResetEntry; @@ -54,8 +54,8 @@ Index: ioemu/vl.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-17 19:47:32.680418959 +0100 -+++ ioemu/vl.h 2006-08-17 19:49:40.120333326 +0100 +--- ioemu.orig/vl.h 2006-12-08 01:26:07.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 01:26:08.000000000 +0000 @@ -131,6 +131,7 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque); diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset index 6588314efe..f91a61a37a 100644 --- a/tools/ioemu/patches/domain-timeoffset +++ b/tools/ioemu/patches/domain-timeoffset @@ -1,7 +1,7 @@ Index: ioemu/hw/mc146818rtc.c =================================================================== ---- ioemu.orig/hw/mc146818rtc.c 2006-10-24 14:45:21.000000000 +0100 -+++ ioemu/hw/mc146818rtc.c 2006-10-24 14:45:39.000000000 +0100 +--- ioemu.orig/hw/mc146818rtc.c 2006-12-08 18:23:40.000000000 +0000 ++++ ioemu/hw/mc146818rtc.c 2006-12-08 18:23:46.000000000 +0000 @@ -178,10 +178,27 @@ } } @@ -46,8 +46,8 @@ Index: ioemu/hw/mc146818rtc.c static void rtc_copy_date(RTCState *s) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-10-24 14:45:38.000000000 +0100 -+++ ioemu/hw/pc.c 2006-10-24 14:45:39.000000000 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 18:23:46.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 18:23:46.000000000 +0000 @@ -159,7 +159,7 @@ } @@ -117,8 +117,8 @@ Index: ioemu/hw/pc.c QEMUMachine pc_machine = { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:45:38.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:45:39.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 18:23:46.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 18:23:46.000000000 +0000 @@ -163,6 +163,8 @@ int xc_handle; @@ -152,7 +152,7 @@ Index: ioemu/vl.c { NULL }, }; -@@ -6248,6 +6253,9 @@ +@@ -6232,6 +6237,9 @@ vcpus = atoi(optarg); fprintf(logfile, "qemu: the number of cpus is %d\n", vcpus); break; @@ -162,7 +162,7 @@ Index: ioemu/vl.c } } } -@@ -6507,7 +6515,8 @@ +@@ -6492,7 +6500,8 @@ machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, @@ -174,8 +174,8 @@ Index: ioemu/vl.c if (usb_enabled) { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:45:38.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:45:39.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 18:23:46.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:23:46.000000000 +0000 @@ -576,7 +576,7 @@ int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/tools/ioemu/patches/fix-interrupt-routing b/tools/ioemu/patches/fix-interrupt-routing new file mode 100644 index 0000000000..b5d8285398 --- /dev/null +++ b/tools/ioemu/patches/fix-interrupt-routing @@ -0,0 +1,459 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID f555a90bcc373a7379bc18f875eac5e7c7122ae9 +# Parent b80f00215bbaf2050765e557f1a017a71e1e8529 +[HVM] Reworked interrupt distribution logic. + +TODO: + 1. Fix IO-APIC ID to not conflict with LAPIC IDS. + 2. Fix i8259 device model (seems to work already though!). + 3. Add INTSRC overrides in MPBIOS and ACPI tables so + that PCI legacy IRQ routing always ends up at an + IO-APIC input with level trigger. Restricting link + routing to {5,6,10,11} and setting overrides for all + four of those would work. + +Signed-off-by: Keir Fraser + +Index: ioemu/Makefile.target +=================================================================== +--- ioemu.orig/Makefile.target 2006-12-08 18:21:56.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 18:22:35.000000000 +0000 +@@ -298,7 +298,7 @@ + ifeq ($(ARCH),ia64) + LIBOBJS=helper2.o exec-dm.o i8259-dm.o + else +-LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o ++LIBOBJS=helper2.o exec-dm.o i8259-dm.o rtc-dm.o piix_pci-dm.o + endif + + all: $(PROGS) +@@ -360,11 +360,11 @@ + # Hardware support + VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) + ifeq ($(ARCH),ia64) +-VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o ++VL_OBJS+= fdc.o mc146818rtc.o serial.o pc.o piix_pci.o + else + VL_OBJS+= fdc.o serial.o pc.o + endif +-VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o ++VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o + VL_OBJS+= usb-uhci.o + VL_OBJS+= piix4acpi.o + VL_OBJS+= xenstore.o +Index: ioemu/target-i386-dm/i8259-dm.c +=================================================================== +--- ioemu.orig/target-i386-dm/i8259-dm.c 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/target-i386-dm/i8259-dm.c 2006-12-08 18:22:35.000000000 +0000 +@@ -33,7 +33,7 @@ + + void pic_set_irq_new(void *opaque, int irq, int level) + { +- xc_hvm_set_irq_level(xc_handle, domid, irq, level); ++ xc_hvm_set_isa_irq_level(xc_handle, domid, irq, level); + } + + /* obsolete function */ +Index: ioemu/target-i386-dm/piix_pci-dm.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/target-i386-dm/piix_pci-dm.c 2006-12-08 18:22:35.000000000 +0000 +@@ -0,0 +1,397 @@ ++/* ++ * QEMU i440FX/PIIX3 PCI Bridge Emulation ++ * ++ * Copyright (c) 2006 Fabrice Bellard ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++ ++#include "vl.h" ++typedef uint32_t pci_addr_t; ++#include "hw/pci_host.h" ++ ++typedef PCIHostState I440FXState; ++ ++static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val) ++{ ++ I440FXState *s = opaque; ++ s->config_reg = val; ++} ++ ++static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr) ++{ ++ I440FXState *s = opaque; ++ return s->config_reg; ++} ++ ++static void i440fx_set_irq(PCIDevice *pci_dev, void *pic, int intx, int level) ++{ ++ xc_hvm_set_pci_intx_level(xc_handle, domid, 0, 0, pci_dev->devfn >> 3, ++ intx, level); ++} ++ ++PCIBus *i440fx_init(void) ++{ ++ PCIBus *b; ++ PCIDevice *d; ++ I440FXState *s; ++ ++ s = qemu_mallocz(sizeof(I440FXState)); ++ b = pci_register_bus(i440fx_set_irq, NULL, 0); ++ s->bus = b; ++ ++ register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s); ++ register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s); ++ ++ register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s); ++ register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s); ++ register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s); ++ register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s); ++ register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s); ++ register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s); ++ ++ d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, ++ NULL, NULL); ++ ++ d->config[0x00] = 0x86; // vendor_id ++ d->config[0x01] = 0x80; ++ d->config[0x02] = 0x37; // device_id ++ d->config[0x03] = 0x12; ++ d->config[0x08] = 0x02; // revision ++ d->config[0x0a] = 0x00; // class_sub = host2pci ++ d->config[0x0b] = 0x06; // class_base = PCI_bridge ++ d->config[0x0e] = 0x00; // header_type ++ return b; ++} ++ ++/* PIIX3 PCI to ISA bridge */ ++ ++static PCIDevice *piix3_dev; ++ ++static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) ++{ ++ /* This is the barber's pole mapping used by Xen. */ ++ return (irq_num + (pci_dev->devfn >> 3)) & 3; ++} ++ ++static void piix3_write_config(PCIDevice *d, ++ uint32_t address, uint32_t val, int len) ++{ ++ int i; ++ ++ /* Scan for updates to PCI link routes (0x60-0x63). */ ++ for (i = 0; i < len; i++) { ++ uint8_t v = (val >> (8*i)) & 0xff; ++ if (v & 0x80) ++ v = 0; ++ v &= 0xf; ++ if (((address+i) >= 0x60) && ((address+i) <= 0x63)) ++ xc_hvm_set_pci_link_route(xc_handle, domid, address + i - 0x60, v); ++ } ++ ++ /* Hand off to default logic. */ ++ pci_default_write_config(d, address, val, len); ++} ++ ++static void piix3_reset(PCIDevice *d) ++{ ++ uint8_t *pci_conf = d->config; ++ ++ pci_conf[0x04] = 0x07; // master, memory and I/O ++ pci_conf[0x05] = 0x00; ++ pci_conf[0x06] = 0x00; ++ pci_conf[0x07] = 0x02; // PCI_status_devsel_medium ++ pci_conf[0x4c] = 0x4d; ++ pci_conf[0x4e] = 0x03; ++ pci_conf[0x4f] = 0x00; ++ pci_conf[0x60] = 0x80; ++ pci_conf[0x61] = 0x80; ++ pci_conf[0x62] = 0x80; ++ pci_conf[0x63] = 0x80; ++ pci_conf[0x69] = 0x02; ++ pci_conf[0x70] = 0x80; ++ pci_conf[0x76] = 0x0c; ++ pci_conf[0x77] = 0x0c; ++ pci_conf[0x78] = 0x02; ++ pci_conf[0x79] = 0x00; ++ pci_conf[0x80] = 0x00; ++ pci_conf[0x82] = 0x00; ++ pci_conf[0xa0] = 0x08; ++ pci_conf[0xa0] = 0x08; ++ pci_conf[0xa2] = 0x00; ++ pci_conf[0xa3] = 0x00; ++ pci_conf[0xa4] = 0x00; ++ pci_conf[0xa5] = 0x00; ++ pci_conf[0xa6] = 0x00; ++ pci_conf[0xa7] = 0x00; ++ pci_conf[0xa8] = 0x0f; ++ pci_conf[0xaa] = 0x00; ++ pci_conf[0xab] = 0x00; ++ pci_conf[0xac] = 0x00; ++ pci_conf[0xae] = 0x00; ++} ++ ++int piix3_init(PCIBus *bus) ++{ ++ PCIDevice *d; ++ uint8_t *pci_conf; ++ ++ d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice), ++ -1, NULL, piix3_write_config); ++ register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d); ++ ++ piix3_dev = d; ++ pci_conf = d->config; ++ ++ pci_conf[0x00] = 0x86; // Intel ++ pci_conf[0x01] = 0x80; ++ pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) ++ pci_conf[0x03] = 0x70; ++ pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA ++ pci_conf[0x0b] = 0x06; // class_base = PCI_bridge ++ pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic ++ ++ piix3_reset(d); ++ return d->devfn; ++} ++ ++/***********************************************************/ ++/* XXX: the following should be moved to the PC BIOS */ ++ ++static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) ++{ ++ return cpu_inb(NULL, addr); ++} ++ ++static void isa_outb(uint32_t val, uint32_t addr) ++{ ++ cpu_outb(NULL, addr, val); ++} ++ ++static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) ++{ ++ return cpu_inw(NULL, addr); ++} ++ ++static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) ++{ ++ cpu_outw(NULL, addr, val); ++} ++ ++static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) ++{ ++ return cpu_inl(NULL, addr); ++} ++ ++static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) ++{ ++ cpu_outl(NULL, addr, val); ++} ++ ++static uint32_t pci_bios_io_addr; ++static uint32_t pci_bios_mem_addr; ++/* host irqs corresponding to PCI irqs A-D */ ++static uint8_t pci_irqs[4] = { 10, 11, 10, 11 }; ++ ++static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) ++{ ++ PCIBus *s = d->bus; ++ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ++ pci_data_write(s, addr, val, 4); ++} ++ ++static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) ++{ ++ PCIBus *s = d->bus; ++ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ++ pci_data_write(s, addr, val, 2); ++} ++ ++static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) ++{ ++ PCIBus *s = d->bus; ++ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ++ pci_data_write(s, addr, val, 1); ++} ++ ++static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) ++{ ++ PCIBus *s = d->bus; ++ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ++ return pci_data_read(s, addr, 4); ++} ++ ++static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) ++{ ++ PCIBus *s = d->bus; ++ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ++ return pci_data_read(s, addr, 2); ++} ++ ++static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) ++{ ++ PCIBus *s = d->bus; ++ addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); ++ return pci_data_read(s, addr, 1); ++} ++ ++static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) ++{ ++ PCIIORegion *r; ++ uint16_t cmd; ++ uint32_t ofs; ++ ++ if ( region_num == PCI_ROM_SLOT ) { ++ ofs = 0x30; ++ }else{ ++ ofs = 0x10 + region_num * 4; ++ } ++ ++ pci_config_writel(d, ofs, addr); ++ r = &d->io_regions[region_num]; ++ ++ /* enable memory mappings */ ++ cmd = pci_config_readw(d, PCI_COMMAND); ++ if ( region_num == PCI_ROM_SLOT ) ++ cmd |= 2; ++ else if (r->type & PCI_ADDRESS_SPACE_IO) ++ cmd |= 1; ++ else ++ cmd |= 2; ++ pci_config_writew(d, PCI_COMMAND, cmd); ++} ++ ++static void pci_bios_init_device(PCIDevice *d) ++{ ++ int class; ++ PCIIORegion *r; ++ uint32_t *paddr; ++ int i, pin, pic_irq, vendor_id, device_id; ++ ++ class = pci_config_readw(d, PCI_CLASS_DEVICE); ++ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ++ device_id = pci_config_readw(d, PCI_DEVICE_ID); ++ switch(class) { ++ case 0x0101: ++ if (vendor_id == 0x8086 && device_id == 0x7010) { ++ /* PIIX3 IDE */ ++ pci_config_writew(d, 0x40, 0x8000); // enable IDE0 ++ pci_config_writew(d, 0x42, 0x8000); // enable IDE1 ++ goto default_map; ++ } else { ++ /* IDE: we map it as in ISA mode */ ++ pci_set_io_region_addr(d, 0, 0x1f0); ++ pci_set_io_region_addr(d, 1, 0x3f4); ++ pci_set_io_region_addr(d, 2, 0x170); ++ pci_set_io_region_addr(d, 3, 0x374); ++ } ++ break; ++ case 0x0680: ++ if (vendor_id == 0x8086 && device_id == 0x7113) { ++ /* ++ * PIIX4 ACPI PM. ++ * Special device with special PCI config space. No ordinary BARs. ++ */ ++ pci_config_writew(d, 0x20, 0x0000); // No smb bus IO enable ++ pci_config_writew(d, 0x22, 0x0000); ++ pci_config_writew(d, 0x3c, 0x0009); // Hardcoded IRQ9 ++ pci_config_writew(d, 0x3d, 0x0001); ++ } ++ break; ++ case 0x0300: ++ if (vendor_id != 0x1234) ++ goto default_map; ++ /* VGA: map frame buffer to default Bochs VBE address */ ++ pci_set_io_region_addr(d, 0, 0xE0000000); ++ break; ++ case 0x0800: ++ /* PIC */ ++ vendor_id = pci_config_readw(d, PCI_VENDOR_ID); ++ device_id = pci_config_readw(d, PCI_DEVICE_ID); ++ if (vendor_id == 0x1014) { ++ /* IBM */ ++ if (device_id == 0x0046 || device_id == 0xFFFF) { ++ /* MPIC & MPIC2 */ ++ pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); ++ } ++ } ++ break; ++ case 0xff00: ++ if (vendor_id == 0x0106b && ++ (device_id == 0x0017 || device_id == 0x0022)) { ++ /* macio bridge */ ++ pci_set_io_region_addr(d, 0, 0x80800000); ++ } ++ break; ++ default: ++ default_map: ++ /* default memory mappings */ ++ for(i = 0; i < PCI_NUM_REGIONS; i++) { ++ r = &d->io_regions[i]; ++ if (r->size) { ++ if (r->type & PCI_ADDRESS_SPACE_IO) ++ paddr = &pci_bios_io_addr; ++ else ++ paddr = &pci_bios_mem_addr; ++ *paddr = (*paddr + r->size - 1) & ~(r->size - 1); ++ pci_set_io_region_addr(d, i, *paddr); ++ *paddr += r->size; ++ } ++ } ++ break; ++ } ++ ++ /* map the interrupt */ ++ pin = pci_config_readb(d, PCI_INTERRUPT_PIN); ++ if (pin != 0) { ++ pin = pci_slot_get_pirq(d, pin - 1); ++ pic_irq = pci_irqs[pin]; ++ pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); ++ } ++} ++ ++/* ++ * This function initializes the PCI devices as a normal PCI BIOS ++ * would do. It is provided just in case the BIOS has no support for ++ * PCI. ++ */ ++void pci_bios_init(void) ++{ ++ int i, irq; ++ uint8_t elcr[2]; ++ ++ pci_bios_io_addr = 0xc000; ++ pci_bios_mem_addr = HVM_BELOW_4G_MMIO_START; ++ ++ /* activate IRQ mappings */ ++ elcr[0] = 0x00; ++ elcr[1] = 0x00; ++ for(i = 0; i < 4; i++) { ++ irq = pci_irqs[i]; ++ /* set to trigger level */ ++ elcr[irq >> 3] |= (1 << (irq & 7)); ++ /* activate irq remapping in PIIX */ ++ pci_config_writeb(piix3_dev, 0x60 + i, irq); ++ } ++ isa_outb(elcr[0], 0x4d0); ++ isa_outb(elcr[1], 0x4d1); ++ ++ pci_for_each_device(pci_bios_init_device); ++} ++ diff --git a/tools/ioemu/patches/hypervisor-pit b/tools/ioemu/patches/hypervisor-pit index 8d151a1b95..012254f615 100644 --- a/tools/ioemu/patches/hypervisor-pit +++ b/tools/ioemu/patches/hypervisor-pit @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-17 19:49:33.813030472 +0100 -+++ ioemu/Makefile.target 2006-08-17 19:49:50.228216099 +0100 -@@ -354,7 +354,7 @@ +--- ioemu.orig/Makefile.target 2006-12-08 01:41:12.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:12.000000000 +0000 +@@ -355,7 +355,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) @@ -13,8 +13,8 @@ Index: ioemu/Makefile.target DEFINES += -DHAS_AUDIO Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-17 19:49:35.507843144 +0100 -+++ ioemu/hw/pc.c 2006-08-17 19:49:50.229215988 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 01:41:12.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 01:41:12.000000000 +0000 @@ -38,7 +38,9 @@ static fdctrl_t *floppy_controller; @@ -38,8 +38,8 @@ Index: ioemu/hw/pc.c pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic); Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-17 19:49:48.566399780 +0100 -+++ ioemu/vl.c 2006-08-17 19:49:50.231215767 +0100 +--- ioemu.orig/vl.c 2006-12-08 01:41:12.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 01:41:12.000000000 +0000 @@ -5570,6 +5570,7 @@ #ifdef HAS_AUDIO diff --git a/tools/ioemu/patches/hypervisor-rtc b/tools/ioemu/patches/hypervisor-rtc index 7563425e3b..a3357ea9bd 100644 --- a/tools/ioemu/patches/hypervisor-rtc +++ b/tools/ioemu/patches/hypervisor-rtc @@ -5,9 +5,11 @@ [HVM] Move RTC emulation into the hypervisor. Signed-off-by: Xiaowei Yang ---- ioemu/Makefile.target Wed Oct 18 18:13:57 2006 +0100 -+++ ioemu/Makefile.target Wed Oct 18 18:35:21 2006 +0100 -@@ -294,7 +294,11 @@ endif +Index: ioemu/Makefile.target +=================================================================== +--- ioemu.orig/Makefile.target 2006-12-08 01:41:15.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:15.000000000 +0000 +@@ -295,7 +295,11 @@ endif # qemu-dm objects @@ -19,7 +21,7 @@ Signed-off-by: Xiaowei Yang all: $(PROGS) -@@ -354,7 +358,11 @@ ifeq ($(TARGET_BASE_ARCH), i386) +@@ -355,7 +359,11 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) @@ -31,8 +33,10 @@ Signed-off-by: Xiaowei Yang VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o VL_OBJS+= usb-uhci.o VL_OBJS+= piix4acpi.o ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ ioemu/target-i386-dm/rtc-dm.c Wed Oct 18 18:35:21 2006 +0100 +Index: ioemu/target-i386-dm/rtc-dm.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/target-i386-dm/rtc-dm.c 2006-12-08 01:41:15.000000000 +0000 @@ -0,0 +1,107 @@ +/* + * QEMU MC146818 RTC emulation diff --git a/tools/ioemu/patches/ide-error-reporting b/tools/ioemu/patches/ide-error-reporting new file mode 100644 index 0000000000..7314a49c06 --- /dev/null +++ b/tools/ioemu/patches/ide-error-reporting @@ -0,0 +1,110 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID fd28a1b139dea91b8bfcf06dd233dbdda8f51ff1 +# Parent d8befb109c394c2c2d3e1870a500107d461724ef +[QEMU] Error reporting in IDE device model. + +Following on from my patch to make blktap report I/O errors back to +guest OS, a similar problem exists in the QEMU codebase. The IDE +driver never reports I/O errors during read/write operations back to +the guest OS. Instead all I/O operations are reported as +succesfull. If, for example, the host FS holding the disk image fills +up, then writes may fail due to lack of space. Since the guest OS +never sees these failures, it assumes all is well & will continue +writing. Eventually this can lead to severe & unrecoverable filesystem +corruption. + +The attached patch fixes QEMU ide driver such that any failure of a +read or write operation sets the appropriate IDE status/error +registers. Having read the ATA-6 spec I think the most compliant +behaviour is to set the status register to 'READY_STAT | ERR_STAT', +and the error register to ABRT_ERR. There is already a convenience +function ide_abort_command() in the QEMU codebase which does just +this, so the attached patch simply calls that function. + +With this patch the guest OS sees the I/O failure & the kernel logs +IDE errors and then retries the operation. This at least ensures that +the guest can be shutdown the out of space issue in the host corrected +and the guest restarted, without any serious filesystem damage having +occurred. + +From: Daniel Berrange +Signed-off-by: Keir Fraser + +Index: ioemu/hw/ide.c +=================================================================== +--- ioemu.orig/hw/ide.c 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/hw/ide.c 2006-12-08 18:23:18.000000000 +0000 +@@ -680,7 +680,7 @@ + static void ide_sector_read(IDEState *s) + { + int64_t sector_num; +- int ret, n; ++ int n; + + s->status = READY_STAT | SEEK_STAT; + s->error = 0; /* not needed by IDE spec, but needed by Windows */ +@@ -695,7 +695,11 @@ + #endif + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; +- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); ++ if (bdrv_read(s->bs, sector_num, s->io_buffer, n) != 0) { ++ ide_abort_command(s); ++ ide_set_irq(s); ++ return; ++ } + ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read); + ide_set_irq(s); + ide_set_sector(s, sector_num + n); +@@ -721,7 +725,11 @@ + if (n > MAX_MULT_SECTORS) + n = MAX_MULT_SECTORS; + sector_num = ide_get_sector(s); +- bdrv_read(s->bs, sector_num, s->io_buffer, n); ++ if (bdrv_read(s->bs, sector_num, s->io_buffer, n) != 0) { ++ ide_abort_command(s); ++ ide_set_irq(s); ++ return 0; ++ } + s->io_buffer_index = 0; + s->io_buffer_size = n * 512; + len = s->io_buffer_size; +@@ -767,7 +775,7 @@ + static void ide_sector_write(IDEState *s) + { + int64_t sector_num; +- int ret, n, n1; ++ int n, n1; + + s->status = READY_STAT | SEEK_STAT; + sector_num = ide_get_sector(s); +@@ -777,7 +785,11 @@ + n = s->nsector; + if (n > s->req_nb_sectors) + n = s->req_nb_sectors; +- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); ++ if (bdrv_write(s->bs, sector_num, s->io_buffer, n) != 0) { ++ ide_abort_command(s); ++ ide_set_irq(s); ++ return; ++ } + s->nsector -= n; + if (s->nsector == 0) { + /* no more sector to write */ +@@ -823,8 +835,13 @@ + if (len == 0) { + n = s->io_buffer_size >> 9; + sector_num = ide_get_sector(s); +- bdrv_write(s->bs, sector_num, s->io_buffer, +- s->io_buffer_size >> 9); ++ if (bdrv_write(s->bs, sector_num, s->io_buffer, ++ s->io_buffer_size >> 9) != 0) { ++ ide_abort_command(s); ++ ide_set_irq(s); ++ return 0; ++ } ++ + sector_num += n; + ide_set_sector(s, sector_num); + s->nsector -= n; diff --git a/tools/ioemu/patches/ioemu-ia64 b/tools/ioemu/patches/ioemu-ia64 index b108178f73..d8afe7fe3c 100644 --- a/tools/ioemu/patches/ioemu-ia64 +++ b/tools/ioemu/patches/ioemu-ia64 @@ -1,7 +1,7 @@ Index: ioemu/hw/iommu.c =================================================================== ---- ioemu.orig/hw/iommu.c 2006-08-17 19:37:36.791476068 +0100 -+++ ioemu/hw/iommu.c 2006-08-17 19:48:27.357375720 +0100 +--- ioemu.orig/hw/iommu.c 2006-12-08 02:02:07.000000000 +0000 ++++ ioemu/hw/iommu.c 2006-12-08 02:02:34.000000000 +0000 @@ -82,7 +82,11 @@ #define IOPTE_VALID 0x00000002 /* IOPTE is valid */ #define IOPTE_WAZ 0x00000001 /* Write as zeros */ @@ -16,8 +16,8 @@ Index: ioemu/hw/iommu.c Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-08-17 19:37:36.791476068 +0100 -+++ ioemu/cpu-all.h 2006-08-17 19:48:27.358375609 +0100 +--- ioemu.orig/cpu-all.h 2006-12-08 02:02:07.000000000 +0000 ++++ ioemu/cpu-all.h 2006-12-08 02:02:34.000000000 +0000 @@ -835,6 +835,31 @@ :"=m" (*(volatile long *)addr) :"dIr" (nr)); @@ -52,36 +52,36 @@ Index: ioemu/cpu-all.h /* memory API */ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-17 19:47:08.538087284 +0100 -+++ ioemu/vl.c 2006-08-17 19:57:50.666108706 +0100 -@@ -6144,6 +6144,11 @@ - - xc_handle = xc_interface_open(); +--- ioemu.orig/vl.c 2006-12-08 02:02:28.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:34.000000000 +0000 +@@ -6137,6 +6137,11 @@ + exit(1); + } +#if defined (__ia64__) + if (ram_size > MMIO_START) + ram_size += 1 * MEM_G; /* skip 3G-4G MMIO, LEGACY_IO_SPACE etc. */ +#endif + - nr_pages = ram_size/PAGE_SIZE; - tmp_nr_pages = nr_pages; + /* init the memory */ + phys_ram_size = ram_size + vga_ram_size + bios_size; @@ -6161,6 +6166,7 @@ exit(-1); } +#if defined(__i386__) || defined(__x86_64__) - if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) { - fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno); - exit(-1); -@@ -6191,6 +6197,41 @@ + for ( i = 0; i < tmp_nr_pages; i++) + page_array[i] = i; + +@@ -6185,6 +6191,48 @@ free(page_array); +#elif defined(__ia64__) + + if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, -+ IO_PAGE_START >> PAGE_SHIFT, 1) != 1) { ++ IO_PAGE_START >> PAGE_SHIFT, 3) != 3) { + fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); + exit(-1); + } @@ -93,6 +93,12 @@ Index: ioemu/vl.c + fprintf(logfile, "shared page at pfn:%lx, mfn: %016lx\n", + IO_PAGE_START >> PAGE_SHIFT, page_array[0]); + ++ buffered_io_page =xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, ++ PROT_READ|PROT_WRITE, ++ page_array[2]); ++ fprintf(logfile, "Buffered IO page at pfn:%lx, mfn: %016lx\n", ++ BUFFER_IO_PAGE_START >> PAGE_SHIFT, page_array[2]); ++ + if (xc_ia64_get_pfn_list(xc_handle, domid, + page_array, 0, nr_pages) != nr_pages) { + fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); @@ -100,9 +106,9 @@ Index: ioemu/vl.c + } + + if (ram_size > MMIO_START) { -+ for (i = 0 ; i < MEM_G >> PAGE_SHIFT; i++) -+ page_array[MMIO_START >> PAGE_SHIFT + i] = -+ page_array[IO_PAGE_START >> PAGE_SHIFT + 1]; ++ for (i = 0 ; i < (MEM_G >> PAGE_SHIFT); i++) ++ page_array[(MMIO_START >> PAGE_SHIFT) + i] = ++ page_array[(IO_PAGE_START >> PAGE_SHIFT) + 1]; + } + + phys_ram_base = xc_map_foreign_batch(xc_handle, domid, @@ -112,52 +118,15 @@ Index: ioemu/vl.c + fprintf(logfile, "xc_map_foreign_batch returned error %d\n", errno); + exit(-1); + } ++ free(page_array); +#endif #else /* !CONFIG_DM */ phys_ram_base = qemu_vmalloc(phys_ram_size); -Index: ioemu/target-i386-dm/exec-dm.c -=================================================================== ---- ioemu.orig/target-i386-dm/exec-dm.c 2006-08-17 19:37:36.792475957 +0100 -+++ ioemu/target-i386-dm/exec-dm.c 2006-08-17 19:48:27.361375278 +0100 -@@ -341,6 +341,23 @@ - return io_mem_read[io_index >> IO_MEM_SHIFT]; - } - -+#ifdef __ia64__ -+/* IA64 has seperate I/D cache, with coherence maintained by DMA controller. -+ * So to emulate right behavior that guest OS is assumed, we need to flush -+ * I/D cache here. -+ */ -+static void sync_icache(unsigned long address, int len) -+{ -+ int l; -+ -+ for(l = 0; l < (len + 32); l += 32) -+ __ia64_fc(address + l); -+ -+ ia64_sync_i(); -+ ia64_srlz_i(); -+} -+#endif -+ - /* physical memory access (slow version, mainly for debug) */ - #if defined(CONFIG_USER_ONLY) - void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, -@@ -432,6 +449,9 @@ - /* RAM case */ - ptr = phys_ram_base + addr1; - memcpy(ptr, buf, l); -+#ifdef __ia64__ -+ sync_icache((unsigned long)ptr, l); -+#endif - } - } else { - if (io_index) { Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-08-17 19:37:36.791476068 +0100 -+++ ioemu/exec-all.h 2006-08-17 19:48:27.362375167 +0100 +--- ioemu.orig/exec-all.h 2006-12-08 02:02:07.000000000 +0000 ++++ ioemu/exec-all.h 2006-12-08 02:02:34.000000000 +0000 @@ -462,12 +462,13 @@ } #endif @@ -177,9 +146,9 @@ Index: ioemu/exec-all.h Index: ioemu/target-i386-dm/cpu.h =================================================================== ---- ioemu.orig/target-i386-dm/cpu.h 2006-08-17 19:37:36.792475957 +0100 -+++ ioemu/target-i386-dm/cpu.h 2006-08-17 19:48:27.362375167 +0100 -@@ -80,7 +80,11 @@ +--- ioemu.orig/target-i386-dm/cpu.h 2006-12-08 02:02:07.000000000 +0000 ++++ ioemu/target-i386-dm/cpu.h 2006-12-08 02:02:34.000000000 +0000 +@@ -78,7 +78,11 @@ /* helper2.c */ int main_loop(void); @@ -194,7 +163,7 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/ia64_intrinsic.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/ia64_intrinsic.h 2006-08-17 19:48:27.363375057 +0100 ++++ ioemu/ia64_intrinsic.h 2006-12-08 02:02:34.000000000 +0000 @@ -0,0 +1,276 @@ +#ifndef IA64_INTRINSIC_H +#define IA64_INTRINSIC_H diff --git a/tools/ioemu/patches/limit-fdc-sector-size-to-16K b/tools/ioemu/patches/limit-fdc-sector-size-to-16K new file mode 100644 index 0000000000..e97973fcec --- /dev/null +++ b/tools/ioemu/patches/limit-fdc-sector-size-to-16K @@ -0,0 +1,32 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID f711b87ba951e608287abd0de028c6f0d83400a9 +# Parent f3ee62b7fb5299c89d442845e0883bcfab78c067 +[QEMU] fdc: Limit sector size to 16K + +In fdctrl_start_transfer the sector size field (fifo[5]) is not +checked for overflows. This allows an arbitrarily large sector size +to be used, which can in turn result in a negative data_len field that +is then used for DMA transfers. + +This can lead to the corrpuption of qemu state because some subsequent +checks on the transfer length is conducted using signed integers. + +This patch limits the value fifo[5] to 7 which is the standard limit +on floppy sector size. + +Signed-off-by: Herbert Xu + +Index: ioemu/hw/fdc.c +=================================================================== +--- ioemu.orig/hw/fdc.c 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/hw/fdc.c 2006-12-08 18:22:57.000000000 +0000 +@@ -898,7 +898,7 @@ + fdctrl->data_len = fdctrl->fifo[8]; + } else { + int tmp; +- fdctrl->data_len = 128 << fdctrl->fifo[5]; ++ fdctrl->data_len = 128 << (fdctrl->fifo[5] > 7 ? 7 : fdctrl->fifo[5]); + tmp = (cur_drv->last_sect - ks + 1); + if (fdctrl->fifo[0] & 0x80) + tmp += cur_drv->last_sect; diff --git a/tools/ioemu/patches/ne2000-bounds-checks b/tools/ioemu/patches/ne2000-bounds-checks new file mode 100644 index 0000000000..5cd37e4aa9 --- /dev/null +++ b/tools/ioemu/patches/ne2000-bounds-checks @@ -0,0 +1,113 @@ +# HG changeset patch +# User kaf24@localhost.localdomain +# Node ID 66fe61db9e69e03e12d0c4086683bebfb4a67780 +# Parent 1940ee13f9d6ab1be2c614a0fbf7769536a056d2 +[QEMU] ne2000: Stop memory access beyond buffer + +As a program that runs in dom0 which serves users from guests, +the qemu drivers need to be vigilant to the input that comes +from the guests since they may be malicious. + +As it is there are multiple ways to get ne2000 to read/write +memory beyond the 48K buffer that it has allocated for each +adapter. + +This patch checks the addresses and prevents this from occuring. + +The boundary is checked each time since it's changed for every +packet received while the other parameters are only changed +(by the guest) during setup. + +Signed-off: Herbert Xu + +Index: ioemu/hw/ne2000.c +=================================================================== +--- ioemu.orig/hw/ne2000.c 2006-12-08 18:20:45.000000000 +0000 ++++ ioemu/hw/ne2000.c 2006-12-08 18:20:53.000000000 +0000 +@@ -137,6 +137,7 @@ + uint8_t curpag; + uint8_t mult[8]; /* multicast mask array */ + int irq; ++ int tainted; + PCIDevice *pci_dev; + VLANClientState *vc; + uint8_t macaddr[6]; +@@ -226,6 +227,27 @@ + + #define MIN_BUF_SIZE 60 + ++static inline int ne2000_valid_ring_addr(NE2000State *s, unsigned int addr) ++{ ++ addr <<= 8; ++ return addr < s->stop && addr >= s->start; ++} ++ ++static inline int ne2000_check_state(NE2000State *s) ++{ ++ if (!s->tainted) ++ return 0; ++ ++ if (s->start >= s->stop || s->stop > NE2000_MEM_SIZE) ++ return -EINVAL; ++ ++ if (!ne2000_valid_ring_addr(s, s->curpag)) ++ return -EINVAL; ++ ++ s->tainted = 0; ++ return 0; ++} ++ + static void ne2000_receive(void *opaque, const uint8_t *buf, int size) + { + NE2000State *s = opaque; +@@ -239,6 +261,12 @@ + printf("NE2000: received len=%d\n", size); + #endif + ++ if (ne2000_check_state(s)) ++ return; ++ ++ if (!ne2000_valid_ring_addr(s, s->boundary)) ++ return; ++ + if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) + return; + +@@ -359,9 +387,11 @@ + switch(offset) { + case EN0_STARTPG: + s->start = val << 8; ++ s->tainted = 1; + break; + case EN0_STOPPG: + s->stop = val << 8; ++ s->tainted = 1; + break; + case EN0_BOUNDARY: + s->boundary = val; +@@ -406,6 +436,7 @@ + break; + case EN1_CURPAG: + s->curpag = val; ++ s->tainted = 1; + break; + case EN1_MULT ... EN1_MULT + 7: + s->mult[offset - EN1_MULT] = val; +@@ -509,7 +540,7 @@ + { + addr &= ~1; /* XXX: check exact behaviour if not even */ + if (addr < 32 || +- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { ++ (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) { + cpu_to_le32wu((uint32_t *)(s->mem + addr), val); + } + } +@@ -539,7 +570,7 @@ + { + addr &= ~1; /* XXX: check exact behaviour if not even */ + if (addr < 32 || +- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { ++ (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE - 2)) { + return le32_to_cpupu((uint32_t *)(s->mem + addr)); + } else { + return 0xffffffff; diff --git a/tools/ioemu/patches/nodelay-serial-over-tcp b/tools/ioemu/patches/nodelay-serial-over-tcp new file mode 100644 index 0000000000..ec3bde9d95 --- /dev/null +++ b/tools/ioemu/patches/nodelay-serial-over-tcp @@ -0,0 +1,29 @@ +# HG changeset patch +# User PeterJohnston +# Node ID b8cc9ffda0a3dc449b026c72c97f78dea2e6f114 +# Parent a8d2b1393b769048c7b62822e45bef27eef80fb6 +[QEMU] Add TCP_NODELAY to tcp connections exporting serial ports. + +Signed-off-by: Steven Smith + +Index: ioemu/vl.c +=================================================================== +--- ioemu.orig/vl.c 2006-12-08 18:21:56.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 18:22:42.000000000 +0000 +@@ -2530,6 +2530,7 @@ + int is_waitconnect = 1; + const char *ptr; + struct sockaddr_in saddr; ++ int opt; + + if (parse_host_port(&saddr, host_str) < 0) + goto fail; +@@ -2598,6 +2599,8 @@ + } + } + s->fd = fd; ++ opt = 1; ++ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt)); + if (s->connected) + tcp_chr_connect(chr); + else diff --git a/tools/ioemu/patches/qemu-bootorder b/tools/ioemu/patches/qemu-bootorder index e162320bdd..e0142b4313 100644 --- a/tools/ioemu/patches/qemu-bootorder +++ b/tools/ioemu/patches/qemu-bootorder @@ -1,7 +1,7 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:02:38.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:38.000000000 +0000 @@ -125,7 +125,7 @@ struct sockaddr_in vnclisten_addr; const char* keyboard_layout = NULL; @@ -11,7 +11,7 @@ Index: ioemu/vl.c uint64_t ram_size; int pit_min_timer_count = 0; int nb_nics; -@@ -6075,14 +6075,14 @@ +@@ -6059,14 +6059,14 @@ break; #endif /* !CONFIG_DM */ case QEMU_OPTION_boot: @@ -32,7 +32,7 @@ Index: ioemu/vl.c exit(1); } break; -@@ -6349,6 +6349,7 @@ +@@ -6333,6 +6333,7 @@ fd_filename[0] == '\0') help(); @@ -40,7 +40,7 @@ Index: ioemu/vl.c /* boot to cd by default if no hard disk */ if (hd_filename[0] == '\0' && boot_device == 'c') { if (fd_filename[0] != '\0') -@@ -6356,6 +6357,7 @@ +@@ -6340,6 +6341,7 @@ else boot_device = 'd'; } @@ -48,7 +48,7 @@ Index: ioemu/vl.c #endif /* !CONFIG_DM */ setvbuf(stdout, NULL, _IOLBF, 0); -@@ -6614,6 +6616,7 @@ +@@ -6598,6 +6600,7 @@ ds, fd_filename, snapshot, kernel_filename, kernel_cmdline, initrd_filename, timeoffset); @@ -58,8 +58,8 @@ Index: ioemu/vl.c if (usb_enabled) { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:33:47.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:38.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:38.000000000 +0000 @@ -578,7 +578,7 @@ #ifndef QEMU_TOOL @@ -80,8 +80,8 @@ Index: ioemu/vl.h uint32_t initrd_image, uint32_t initrd_size, Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/hw/pc.c 2006-10-24 14:33:47.000000000 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 02:02:38.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 02:02:38.000000000 +0000 @@ -158,8 +158,23 @@ rtc_set_memory(s, info_ofs + 8, sectors); } diff --git a/tools/ioemu/patches/qemu-daemonize b/tools/ioemu/patches/qemu-daemonize index 51568fe2ff..0a3d087460 100644 --- a/tools/ioemu/patches/qemu-daemonize +++ b/tools/ioemu/patches/qemu-daemonize @@ -2,9 +2,9 @@ Changes required because qemu-dm runs daemonized. Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100 -@@ -6054,10 +6054,11 @@ +--- ioemu.orig/vl.c 2006-12-08 02:00:42.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:00:42.000000000 +0000 +@@ -6038,10 +6038,11 @@ } break; case QEMU_OPTION_nographic: diff --git a/tools/ioemu/patches/qemu-dm b/tools/ioemu/patches/qemu-dm index 056ce40e3a..472cf61428 100644 --- a/tools/ioemu/patches/qemu-dm +++ b/tools/ioemu/patches/qemu-dm @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/Makefile.target 2006-08-06 02:14:09.794902973 +0100 -@@ -302,7 +302,7 @@ +--- ioemu.orig/Makefile.target 2006-12-08 01:41:05.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:10.000000000 +0000 +@@ -303,7 +303,7 @@ endif # must use static linking to avoid leaving stuff in virtual address space @@ -13,8 +13,8 @@ Index: ioemu/Makefile.target VL_OBJS+=tap-win32.o Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/configure 2006-08-06 02:14:09.795902861 +0100 +--- ioemu.orig/configure 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/configure 2006-12-08 01:41:10.000000000 +0000 @@ -75,8 +75,8 @@ bigendian="no" mingw32="no" @@ -37,8 +37,8 @@ Index: ioemu/configure target_user_only="yes" Index: ioemu/cpu-all.h =================================================================== ---- ioemu.orig/cpu-all.h 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/cpu-all.h 2006-08-06 02:14:09.796902750 +0100 +--- ioemu.orig/cpu-all.h 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/cpu-all.h 2006-12-08 01:41:10.000000000 +0000 @@ -690,7 +690,9 @@ void page_set_flags(target_ulong start, target_ulong end, int flags); void page_unprotect_range(target_ulong data, target_ulong data_size); @@ -64,8 +64,8 @@ Index: ioemu/cpu-all.h void cpu_dump_state(CPUState *env, FILE *f, Index: ioemu/disas.h =================================================================== ---- ioemu.orig/disas.h 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/disas.h 2006-08-06 02:14:09.796902750 +0100 +--- ioemu.orig/disas.h 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/disas.h 2006-12-08 01:41:10.000000000 +0000 @@ -1,6 +1,7 @@ #ifndef _QEMU_DISAS_H #define _QEMU_DISAS_H @@ -83,8 +83,8 @@ Index: ioemu/disas.h #endif /* _QEMU_DISAS_H */ Index: ioemu/exec-all.h =================================================================== ---- ioemu.orig/exec-all.h 2006-08-06 02:14:04.798459982 +0100 -+++ ioemu/exec-all.h 2006-08-06 02:14:09.796902750 +0100 +--- ioemu.orig/exec-all.h 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/exec-all.h 2006-12-08 01:41:10.000000000 +0000 @@ -509,7 +509,7 @@ extern int tb_invalidated_flag; @@ -105,8 +105,8 @@ Index: ioemu/exec-all.h return addr; Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/hw/pc.c 2006-08-06 02:14:09.797902638 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 01:41:10.000000000 +0000 @@ -73,6 +73,7 @@ } } @@ -184,8 +184,8 @@ Index: ioemu/hw/pc.c if (serial_hds[i]) { Index: ioemu/hw/vga_int.h =================================================================== ---- ioemu.orig/hw/vga_int.h 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/hw/vga_int.h 2006-08-06 02:14:09.797902638 +0100 +--- ioemu.orig/hw/vga_int.h 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/hw/vga_int.h 2006-12-08 01:41:10.000000000 +0000 @@ -28,7 +28,7 @@ #define ST01_DISP_ENABLE 0x01 @@ -197,8 +197,8 @@ Index: ioemu/hw/vga_int.h #define VBE_DISPI_MAX_YRES 1200 Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-08-06 02:14:04.798459982 +0100 -+++ ioemu/monitor.c 2006-08-06 02:14:49.574468309 +0100 +--- ioemu.orig/monitor.c 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/monitor.c 2006-12-08 01:41:10.000000000 +0000 @@ -68,6 +68,12 @@ void term_flush(void) @@ -429,8 +429,8 @@ Index: ioemu/monitor.c { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-06 02:14:04.797460093 +0100 -+++ ioemu/vl.c 2006-08-06 02:14:09.802902081 +0100 +--- ioemu.orig/vl.c 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 01:41:10.000000000 +0000 @@ -422,12 +422,15 @@ void hw_error(const char *fmt, ...) { diff --git a/tools/ioemu/patches/qemu-no-apic b/tools/ioemu/patches/qemu-no-apic index a2409da86f..68291defab 100644 --- a/tools/ioemu/patches/qemu-no-apic +++ b/tools/ioemu/patches/qemu-no-apic @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-08-06 02:21:42.270461924 +0100 -+++ ioemu/Makefile.target 2006-08-06 02:22:26.380544784 +0100 -@@ -355,7 +355,7 @@ +--- ioemu.orig/Makefile.target 2006-12-08 01:41:11.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:12.000000000 +0000 +@@ -356,7 +356,7 @@ # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8254.o pcspk.o pc.o @@ -13,8 +13,8 @@ Index: ioemu/Makefile.target endif Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-06 02:22:01.524315611 +0100 -+++ ioemu/hw/pc.c 2006-08-06 02:22:11.875161758 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 01:41:12.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 01:41:12.000000000 +0000 @@ -39,7 +39,9 @@ static fdctrl_t *floppy_controller; static RTCState *rtc_state; diff --git a/tools/ioemu/patches/qemu-pci b/tools/ioemu/patches/qemu-pci index 6f052962c2..7cadbbe7ad 100755 --- a/tools/ioemu/patches/qemu-pci +++ b/tools/ioemu/patches/qemu-pci @@ -1,7 +1,7 @@ Index: ioemu/hw/pci.c =================================================================== ---- ioemu.orig/hw/pci.c 2006-09-21 11:31:14.000000000 +0100 -+++ ioemu/hw/pci.c 2006-09-21 11:31:32.000000000 +0100 +--- ioemu.orig/hw/pci.c 2006-12-08 02:02:05.000000000 +0000 ++++ ioemu/hw/pci.c 2006-12-08 18:16:55.000000000 +0000 @@ -286,6 +286,7 @@ case 0x0b: case 0x0e: @@ -31,8 +31,8 @@ Index: ioemu/hw/pci.c addr++; Index: ioemu/hw/rtl8139.c =================================================================== ---- ioemu.orig/hw/rtl8139.c 2006-09-21 11:31:14.000000000 +0100 -+++ ioemu/hw/rtl8139.c 2006-09-21 11:31:32.000000000 +0100 +--- ioemu.orig/hw/rtl8139.c 2006-12-08 02:02:05.000000000 +0000 ++++ ioemu/hw/rtl8139.c 2006-12-08 18:16:47.000000000 +0000 @@ -3423,6 +3423,8 @@ pci_conf[0x0e] = 0x00; /* header_type */ pci_conf[0x3d] = 1; /* interrupt pin 0 */ @@ -44,8 +44,8 @@ Index: ioemu/hw/rtl8139.c Index: ioemu/hw/usb-uhci.c =================================================================== ---- ioemu.orig/hw/usb-uhci.c 2006-09-21 11:31:14.000000000 +0100 -+++ ioemu/hw/usb-uhci.c 2006-09-21 11:31:32.000000000 +0100 +--- ioemu.orig/hw/usb-uhci.c 2006-12-08 02:02:05.000000000 +0000 ++++ ioemu/hw/usb-uhci.c 2006-12-08 02:02:38.000000000 +0000 @@ -659,6 +659,8 @@ pci_conf[0x0e] = 0x00; // header_type pci_conf[0x3d] = 4; // interrupt pin 3 @@ -55,3 +55,21 @@ Index: ioemu/hw/usb-uhci.c for(i = 0; i < NB_PORTS; i++) { qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach); +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-12-08 18:16:47.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:16:55.000000000 +0000 +@@ -650,8 +650,11 @@ + #define PCI_MAX_LAT 0x3f /* 8 bits */ + + struct PCIDevice { +- /* PCI config space */ +- uint8_t config[256]; ++ /* ++ * PCI config space. The 4 extra bytes are a safety buffer for guest ++ * word/dword writes that can extend past byte 0xff. ++ */ ++ uint8_t config[256+4]; + + /* the following fields are read only */ + PCIBus *bus; diff --git a/tools/ioemu/patches/qemu-serial-fixes b/tools/ioemu/patches/qemu-serial-fixes new file mode 100644 index 0000000000..1afc7a45e8 --- /dev/null +++ b/tools/ioemu/patches/qemu-serial-fixes @@ -0,0 +1,133 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID c33272c2571c7bab7056d8228490700d1df405f9 +# Parent b3d94f4ddffefed8a5cb8dd65a60da9491d460e7 +[HVM] Fix Qemu-dm serial issues: + 1. Retry transmit via a polling timer if a byte cannot be written + immediately to its destination. + 2. Turn off output processing of raw serial lines. + +Signed-off-by: Xiaowei Yang +Signed-off-by: Yunhong Jiang +Signed-off-by: Keir Fraser + +Index: ioemu/vl.c +=================================================================== +--- ioemu.orig/vl.c 2006-12-08 01:28:59.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 01:28:59.000000000 +0000 +@@ -1684,7 +1684,7 @@ + + tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP + |INLCR|IGNCR|ICRNL|IXON); +- tty.c_oflag |= OPOST; ++ tty.c_oflag &= ~OPOST; /* no output mangling of raw serial stream */ + tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); + tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS); + switch(data_bits) { +Index: ioemu/hw/serial.c +=================================================================== +--- ioemu.orig/hw/serial.c 2006-12-08 01:28:17.000000000 +0000 ++++ ioemu/hw/serial.c 2006-12-08 01:29:10.000000000 +0000 +@@ -73,6 +73,11 @@ + #define UART_LSR_OE 0x02 /* Overrun error indicator */ + #define UART_LSR_DR 0x01 /* Receiver data ready */ + ++/* Maximum retries for a single byte transmit. */ ++#define WRITE_MAX_SINGLE_RETRIES 3 ++/* Maximum retries for a sequence of back-to-back unsuccessful transmits. */ ++#define WRITE_MAX_TOTAL_RETRIES 10 ++ + struct SerialState { + uint8_t divider; + uint8_t rbr; /* receive register */ +@@ -93,6 +98,19 @@ + int last_break_enable; + target_ulong base; + int it_shift; ++ ++ /* ++ * If a character transmitted via UART cannot be written to its ++ * destination immediately we remember it here and retry a few times via ++ * a polling timer. ++ * - write_single_retries: Number of write retries for current byte. ++ * - write_total_retries: Number of write retries for back-to-back ++ * unsuccessful transmits. ++ */ ++ int write_single_retries; ++ int write_total_retries; ++ char write_chr; ++ QEMUTimer *write_retry_timer; + }; + + static void serial_update_irq(SerialState *s) +@@ -204,10 +222,37 @@ + tokens_avail--; + } + ++static void serial_chr_write(void *opaque) ++{ ++ SerialState *s = opaque; ++ ++ /* Cancel any outstanding retry if this is a new byte. */ ++ qemu_del_timer(s->write_retry_timer); ++ ++ /* Retry every 100ms for 300ms total. */ ++ if (qemu_chr_write(s->chr, &s->write_chr, 1) == -1) { ++ s->write_total_retries++; ++ if (s->write_single_retries++ >= WRITE_MAX_SINGLE_RETRIES) ++ fprintf(stderr, "serial: write error\n"); ++ else if (s->write_total_retries <= WRITE_MAX_TOTAL_RETRIES) { ++ qemu_mod_timer(s->write_retry_timer, ++ qemu_get_clock(vm_clock) + ticks_per_sec / 10); ++ return; ++ } ++ } else { ++ s->write_total_retries = 0; /* if successful then reset counter */ ++ } ++ ++ /* Success: Notify guest that THR is empty. */ ++ s->thr_ipending = 1; ++ s->lsr |= UART_LSR_THRE; ++ s->lsr |= UART_LSR_TEMT; ++ serial_update_irq(s); ++} ++ + static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) + { + SerialState *s = opaque; +- unsigned char ch; + + addr &= 7; + #ifdef DEBUG_SERIAL +@@ -223,12 +268,9 @@ + s->thr_ipending = 0; + s->lsr &= ~UART_LSR_THRE; + serial_update_irq(s); +- ch = val; +- qemu_chr_write(s->chr, &ch, 1); +- s->thr_ipending = 1; +- s->lsr |= UART_LSR_THRE; +- s->lsr |= UART_LSR_TEMT; +- serial_update_irq(s); ++ s->write_chr = val; ++ s->write_single_retries = 0; ++ serial_chr_write(s); + } + break; + case 1: +@@ -424,6 +466,7 @@ + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; + s->iir = UART_IIR_NO_INT; + s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; ++ s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s); + + register_savevm("serial", base, 1, serial_save, serial_load, s); + +@@ -511,6 +554,7 @@ + s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; + s->base = base; + s->it_shift = it_shift; ++ s->write_retry_timer = qemu_new_timer(vm_clock, serial_chr_write, s); + + register_savevm("serial", base, 1, serial_save, serial_load, s); + diff --git a/tools/ioemu/patches/qemu-target-i386-dm b/tools/ioemu/patches/qemu-target-i386-dm index 8bf4b3ea01..7bb2f9a905 100644 --- a/tools/ioemu/patches/qemu-target-i386-dm +++ b/tools/ioemu/patches/qemu-target-i386-dm @@ -1,7 +1,7 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/Makefile.target 2006-10-24 14:30:56.000000000 +0100 +--- ioemu.orig/Makefile.target 2006-12-08 01:41:10.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:11.000000000 +0000 @@ -62,6 +62,8 @@ QEMU_SYSTEM=qemu-fast endif @@ -11,7 +11,7 @@ Index: ioemu/Makefile.target ifdef CONFIG_USER_ONLY PROGS=$(QEMU_USER) else -@@ -291,6 +293,9 @@ +@@ -292,6 +294,9 @@ OBJS+=gdbstub.o endif @@ -21,7 +21,7 @@ Index: ioemu/Makefile.target all: $(PROGS) $(QEMU_USER): $(OBJS) -@@ -349,7 +354,7 @@ +@@ -350,7 +355,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) @@ -32,8 +32,8 @@ Index: ioemu/Makefile.target DEFINES += -DHAS_AUDIO Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/configure 2006-10-24 14:29:34.000000000 +0100 +--- ioemu.orig/configure 2006-12-08 01:41:10.000000000 +0000 ++++ ioemu/configure 2006-12-08 01:41:11.000000000 +0000 @@ -373,6 +373,8 @@ if [ "$user" = "yes" ] ; then target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user $target_list" @@ -45,8 +45,8 @@ Index: ioemu/configure fi Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/monitor.c 2006-10-24 14:30:56.000000000 +0100 +--- ioemu.orig/monitor.c 2006-12-08 01:41:10.000000000 +0000 ++++ ioemu/monitor.c 2006-12-08 01:41:11.000000000 +0000 @@ -1262,6 +1262,10 @@ "", "show profiling information", }, { "capture", "", do_info_capture, @@ -60,8 +60,8 @@ Index: ioemu/monitor.c Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:30:56.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 01:41:10.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 01:41:11.000000000 +0000 @@ -87,7 +87,7 @@ #include "exec-all.h" @@ -98,8 +98,8 @@ Index: ioemu/vl.c { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:30:56.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 01:40:58.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 01:41:11.000000000 +0000 @@ -37,6 +37,8 @@ #include #include @@ -132,8 +132,8 @@ Index: ioemu/vl.h Index: ioemu/target-i386-dm/cpu.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/cpu.h 2006-10-24 14:30:56.000000000 +0100 -@@ -0,0 +1,86 @@ ++++ ioemu/target-i386-dm/cpu.h 2006-12-08 01:41:11.000000000 +0000 +@@ -0,0 +1,84 @@ +/* + * i386 virtual CPU header + * @@ -191,8 +191,6 @@ Index: ioemu/target-i386-dm/cpu.h + int interrupt_request; + + CPU_COMMON -+ -+ int send_event; +} CPUX86State; + +CPUX86State *cpu_x86_init(void); @@ -223,8 +221,8 @@ Index: ioemu/target-i386-dm/cpu.h Index: ioemu/target-i386-dm/exec-dm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/exec-dm.c 2006-10-24 14:30:56.000000000 +0100 -@@ -0,0 +1,516 @@ ++++ ioemu/target-i386-dm/exec-dm.c 2006-12-08 01:41:11.000000000 +0000 +@@ -0,0 +1,546 @@ +/* + * virtual page mapping and translated block handling + * @@ -259,6 +257,8 @@ Index: ioemu/target-i386-dm/exec-dm.c +#include +#include + ++#include ++ +#include "cpu.h" +#include "exec-all.h" + @@ -568,6 +568,23 @@ Index: ioemu/target-i386-dm/exec-dm.c + return io_mem_read[io_index >> IO_MEM_SHIFT]; +} + ++#ifdef __ia64__ ++/* IA64 has seperate I/D cache, with coherence maintained by DMA controller. ++ * So to emulate right behavior that guest OS is assumed, we need to flush ++ * I/D cache here. ++ */ ++static void sync_icache(unsigned long address, int len) ++{ ++ int l; ++ ++ for(l = 0; l < (len + 32); l += 32) ++ __ia64_fc(address + l); ++ ++ ia64_sync_i(); ++ ia64_srlz_i(); ++} ++#endif ++ +/* physical memory access (slow version, mainly for debug) */ +#if defined(CONFIG_USER_ONLY) +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, @@ -617,22 +634,36 @@ Index: ioemu/target-i386-dm/exec-dm.c + return 0; +} + ++static inline int paddr_is_ram(target_phys_addr_t addr) ++{ ++ /* Is this guest physical address RAM-backed? */ ++#if defined(CONFIG_DM) && (defined(__i386__) || defined(__x86_64__)) ++ if (ram_size <= HVM_BELOW_4G_RAM_END) ++ /* RAM is contiguous */ ++ return (addr < ram_size); ++ else ++ /* There is RAM below and above the MMIO hole */ ++ return ((addr < HVM_BELOW_4G_MMIO_START) || ++ ((addr >= HVM_BELOW_4G_MMIO_START + HVM_BELOW_4G_MMIO_LENGTH) ++ && (addr < ram_size + HVM_BELOW_4G_MMIO_LENGTH))); ++#else ++ return (addr < ram_size); ++#endif ++} ++ +void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) +{ + int l, io_index; + uint8_t *ptr; + uint32_t val; -+ target_phys_addr_t page; -+ unsigned long pd; + + while (len > 0) { -+ page = addr & TARGET_PAGE_MASK; -+ l = (page + TARGET_PAGE_SIZE) - addr; ++ /* How much can we copy before the next page boundary? */ ++ l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); + if (l > len) + l = len; + -+ pd = page; + io_index = iomem_index(addr); + if (is_write) { + if (io_index) { @@ -652,13 +683,12 @@ Index: ioemu/target-i386-dm/exec-dm.c + io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); + l = 1; + } -+ } else { -+ unsigned long addr1; -+ -+ addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); -+ /* RAM case */ -+ ptr = phys_ram_base + addr1; -+ memcpy(ptr, buf, l); ++ } else if (paddr_is_ram(addr)) { ++ /* Reading from RAM */ ++ memcpy(phys_ram_base + addr, buf, l); ++#ifdef __ia64__ ++ sync_icache((unsigned long)(phys_ram_base + addr), l); ++#endif + } + } else { + if (io_index) { @@ -678,14 +708,12 @@ Index: ioemu/target-i386-dm/exec-dm.c + stb_raw(buf, val); + l = 1; + } -+ } else if (addr < ram_size) { -+ /* RAM case */ -+ ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + -+ (addr & ~TARGET_PAGE_MASK); -+ memcpy(buf, ptr, l); ++ } else if (paddr_is_ram(addr)) { ++ /* Reading from RAM */ ++ memcpy(buf, phys_ram_base + addr, l); + } else { -+ /* unreported MMIO space */ -+ memset(buf, 0xff, len); ++ /* Neither RAM nor known MMIO space */ ++ memset(buf, 0xff, len); + } + } + len -= l; @@ -744,8 +772,8 @@ Index: ioemu/target-i386-dm/exec-dm.c Index: ioemu/target-i386-dm/helper2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/helper2.c 2006-10-24 14:31:01.000000000 +0100 -@@ -0,0 +1,469 @@ ++++ ioemu/target-i386-dm/helper2.c 2006-12-08 01:41:11.000000000 +0000 +@@ -0,0 +1,488 @@ +/* + * i386 helpers (without register variable usage) + * @@ -918,10 +946,10 @@ Index: ioemu/target-i386-dm/helper2.c + for (i = 0; i < vcpus; i++) { + req = &(shared_page->vcpu_iodata[i].vp_ioreq); + term_printf("vcpu %d: event port %d\n", i, ioreq_local_port[i]); -+ term_printf(" req state: %x, pvalid: %x, addr: %"PRIx64", " ++ term_printf(" req state: %x, ptr: %x, addr: %"PRIx64", " + "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", -+ req->state, req->pdata_valid, req->addr, -+ req->u.data, req->count, req->size); ++ req->state, req->data_is_ptr, req->addr, ++ req->data, req->count, req->size); + term_printf(" IO totally occurred on this vcpu: %"PRIx64"\n", + req->io_count); + } @@ -934,18 +962,19 @@ Index: ioemu/target-i386-dm/helper2.c + + req = &(shared_page->vcpu_iodata[vcpu].vp_ioreq); + -+ if (req->state == STATE_IOREQ_READY) { -+ req->state = STATE_IOREQ_INPROCESS; -+ rmb(); -+ return req; ++ if (req->state != STATE_IOREQ_READY) { ++ fprintf(logfile, "I/O request not ready: " ++ "%x, ptr: %x, port: %"PRIx64", " ++ "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", ++ req->state, req->data_is_ptr, req->addr, ++ req->data, req->count, req->size); ++ return NULL; + } + -+ fprintf(logfile, "False I/O request ... in-service already: " -+ "%x, pvalid: %x, port: %"PRIx64", " -+ "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", -+ req->state, req->pdata_valid, req->addr, -+ req->u.data, req->count, req->size); -+ return NULL; ++ rmb(); /* see IOREQ_READY /then/ read contents of ioreq */ ++ ++ req->state = STATE_IOREQ_INPROCESS; ++ return req; +} + +//use poll to get the port notification @@ -1030,26 +1059,26 @@ Index: ioemu/target-i386-dm/helper2.c + sign = req->df ? -1 : 1; + + if (req->dir == IOREQ_READ) { -+ if (!req->pdata_valid) { -+ req->u.data = do_inp(env, req->addr, req->size); ++ if (!req->data_is_ptr) { ++ req->data = do_inp(env, req->addr, req->size); + } else { + unsigned long tmp; + + for (i = 0; i < req->count; i++) { + tmp = do_inp(env, req->addr, req->size); -+ write_physical((target_phys_addr_t) req->u.pdata ++ write_physical((target_phys_addr_t) req->data + + (sign * i * req->size), + req->size, &tmp); + } + } + } else if (req->dir == IOREQ_WRITE) { -+ if (!req->pdata_valid) { -+ do_outp(env, req->addr, req->size, req->u.data); ++ if (!req->data_is_ptr) { ++ do_outp(env, req->addr, req->size, req->data); + } else { + for (i = 0; i < req->count; i++) { + unsigned long tmp; + -+ read_physical((target_phys_addr_t) req->u.pdata ++ read_physical((target_phys_addr_t) req->data + + (sign * i * req->size), + req->size, &tmp); + do_outp(env, req->addr, req->size, tmp); @@ -1064,18 +1093,18 @@ Index: ioemu/target-i386-dm/helper2.c + + sign = req->df ? -1 : 1; + -+ if (!req->pdata_valid) { ++ if (!req->data_is_ptr) { + if (req->dir == IOREQ_READ) { + for (i = 0; i < req->count; i++) { + read_physical(req->addr + + (sign * i * req->size), -+ req->size, &req->u.data); ++ req->size, &req->data); + } + } else if (req->dir == IOREQ_WRITE) { + for (i = 0; i < req->count; i++) { + write_physical(req->addr + + (sign * i * req->size), -+ req->size, &req->u.data); ++ req->size, &req->data); + } + } + } else { @@ -1086,13 +1115,13 @@ Index: ioemu/target-i386-dm/helper2.c + read_physical(req->addr + + (sign * i * req->size), + req->size, &tmp); -+ write_physical((target_phys_addr_t )req->u.pdata ++ write_physical((target_phys_addr_t )req->data + + (sign * i * req->size), + req->size, &tmp); + } + } else if (req->dir == IOREQ_WRITE) { + for (i = 0; i < req->count; i++) { -+ read_physical((target_phys_addr_t) req->u.pdata ++ read_physical((target_phys_addr_t) req->data + + (sign * i * req->size), + req->size, &tmp); + write_physical(req->addr @@ -1107,45 +1136,60 @@ Index: ioemu/target-i386-dm/helper2.c +{ + unsigned long tmp1, tmp2; + -+ if (req->pdata_valid != 0) ++ if (req->data_is_ptr != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + if (req->dir == IOREQ_WRITE) { -+ tmp2 = tmp1 & (unsigned long) req->u.data; ++ tmp2 = tmp1 & (unsigned long) req->data; + write_physical(req->addr, req->size, &tmp2); + } -+ req->u.data = tmp1; ++ req->data = tmp1; ++} ++ ++void cpu_ioreq_add(CPUState *env, ioreq_t *req) ++{ ++ unsigned long tmp1, tmp2; ++ ++ if (req->data_is_ptr != 0) ++ hw_error("expected scalar value"); ++ ++ read_physical(req->addr, req->size, &tmp1); ++ if (req->dir == IOREQ_WRITE) { ++ tmp2 = tmp1 + (unsigned long) req->data; ++ write_physical(req->addr, req->size, &tmp2); ++ } ++ req->data = tmp1; +} + +void cpu_ioreq_or(CPUState *env, ioreq_t *req) +{ + unsigned long tmp1, tmp2; + -+ if (req->pdata_valid != 0) ++ if (req->data_is_ptr != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + if (req->dir == IOREQ_WRITE) { -+ tmp2 = tmp1 | (unsigned long) req->u.data; ++ tmp2 = tmp1 | (unsigned long) req->data; + write_physical(req->addr, req->size, &tmp2); + } -+ req->u.data = tmp1; ++ req->data = tmp1; +} + +void cpu_ioreq_xor(CPUState *env, ioreq_t *req) +{ + unsigned long tmp1, tmp2; + -+ if (req->pdata_valid != 0) ++ if (req->data_is_ptr != 0) + hw_error("expected scalar value"); + + read_physical(req->addr, req->size, &tmp1); + if (req->dir == IOREQ_WRITE) { -+ tmp2 = tmp1 ^ (unsigned long) req->u.data; ++ tmp2 = tmp1 ^ (unsigned long) req->data; + write_physical(req->addr, req->size, &tmp2); + } -+ req->u.data = tmp1; ++ req->data = tmp1; +} + +void cpu_handle_ioreq(void *opaque) @@ -1154,9 +1198,9 @@ Index: ioemu/target-i386-dm/helper2.c + ioreq_t *req = cpu_get_ioreq(); + + if (req) { -+ if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) { ++ if ((!req->data_is_ptr) && (req->dir == IOREQ_WRITE)) { + if (req->size != 4) -+ req->u.data &= (1UL << (8 * req->size))-1; ++ req->data &= (1UL << (8 * req->size))-1; + } + + switch (req->type) { @@ -1169,6 +1213,9 @@ Index: ioemu/target-i386-dm/helper2.c + case IOREQ_TYPE_AND: + cpu_ioreq_and(env, req); + break; ++ case IOREQ_TYPE_ADD: ++ cpu_ioreq_add(env, req); ++ break; + case IOREQ_TYPE_OR: + cpu_ioreq_or(env, req); + break; @@ -1179,12 +1226,19 @@ Index: ioemu/target-i386-dm/helper2.c + hw_error("Invalid ioreq type 0x%x\n", req->type); + } + -+ /* No state change if state = STATE_IORESP_HOOK */ -+ if (req->state == STATE_IOREQ_INPROCESS) { -+ mb(); -+ req->state = STATE_IORESP_READY; ++ if (req->state != STATE_IOREQ_INPROCESS) { ++ fprintf(logfile, "Badness in I/O request ... not in service?!: " ++ "%x, ptr: %x, port: %"PRIx64", " ++ "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n", ++ req->state, req->data_is_ptr, req->addr, ++ req->data, req->count, req->size); ++ destroy_hvm_domain(); ++ return; + } -+ env->send_event = 1; ++ ++ wmb(); /* Update ioreq contents /then/ update state. */ ++ req->state = STATE_IORESP_READY; ++ xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); + } +} + @@ -1197,8 +1251,6 @@ Index: ioemu/target-i386-dm/helper2.c + + qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); + -+ env->send_event = 0; -+ + while (1) { + if (vm_running) { + if (shutdown_requested) @@ -1207,19 +1259,14 @@ Index: ioemu/target-i386-dm/helper2.c + + /* Wait up to 10 msec. */ + main_loop_wait(10); -+ -+ if (env->send_event) { -+ env->send_event = 0; -+ xc_evtchn_notify(xce_handle, ioreq_local_port[send_vcpu]); -+ } + } + return 0; +} Index: ioemu/target-i386-dm/i8259-dm.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/i8259-dm.c 2006-10-24 13:47:23.000000000 +0100 -@@ -0,0 +1,107 @@ ++++ ioemu/target-i386-dm/i8259-dm.c 2006-12-08 01:41:11.000000000 +0000 +@@ -0,0 +1,67 @@ +/* Xen 8259 stub for interrupt controller emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard @@ -1244,58 +1291,18 @@ Index: ioemu/target-i386-dm/i8259-dm.c + * THE SOFTWARE. + */ +#include "vl.h" -+ -+/* debug PIC */ -+//#define DEBUG_PIC -+ -+//#define DEBUG_IRQ_LATENCY -+//#define DEBUG_IRQ_COUNT -+ +#include "xenctrl.h" +#include +#include +#include "cpu.h" +#include "cpu-all.h" + -+extern shared_iopage_t *shared_page; -+ +struct PicState2 { +}; + +void pic_set_irq_new(void *opaque, int irq, int level) +{ -+ /* PicState2 *s = opaque; */ -+ global_iodata_t *gio; -+ int mask; -+ -+ gio = &shared_page->sp_global; -+ mask = 1 << irq; -+ if ( gio->pic_elcr & mask ) { -+ /* level */ -+ if ( level ) { -+ atomic_clear_bit(irq, &gio->pic_clear_irr); -+ atomic_set_bit(irq, &gio->pic_irr); -+ cpu_single_env->send_event = 1; -+ } -+ else { -+ atomic_clear_bit(irq, &gio->pic_irr); -+ atomic_set_bit(irq, &gio->pic_clear_irr); -+ cpu_single_env->send_event = 1; -+ } -+ } -+ else { -+ /* edge */ -+ if ( level ) { -+ if ( (mask & gio->pic_last_irr) == 0 ) { -+ atomic_set_bit(irq, &gio->pic_irr); -+ atomic_set_bit(irq, &gio->pic_last_irr); -+ cpu_single_env->send_event = 1; -+ } -+ } -+ else { -+ atomic_clear_bit(irq, &gio->pic_last_irr); -+ } -+ } ++ xc_hvm_set_irq_level(xc_handle, domid, irq, level); +} + +/* obsolete function */ @@ -1330,17 +1337,22 @@ Index: ioemu/target-i386-dm/i8259-dm.c Index: ioemu/target-i386-dm/qemu-dm.debug =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/qemu-dm.debug 2006-10-24 13:47:23.000000000 +0100 -@@ -0,0 +1,5 @@ ++++ ioemu/target-i386-dm/qemu-dm.debug 2006-12-08 01:41:11.000000000 +0000 +@@ -0,0 +1,10 @@ +#!/bin/sh + ++if [ "`arch`" = "x86_64" ]; then ++ LIBDIR="lib64" ++else ++ LIBDIR="lib" ++fi +echo $* > /tmp/args +echo $DISPLAY >> /tmp/args -+exec /usr/lib/xen/bin/qemu-dm $* ++exec /usr/$LIBDIR/xen/bin/qemu-dm $* Index: ioemu/target-i386-dm/qemu-ifup =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/target-i386-dm/qemu-ifup 2006-10-24 13:47:23.000000000 +0100 ++++ ioemu/target-i386-dm/qemu-ifup 2006-12-08 01:41:11.000000000 +0000 @@ -0,0 +1,10 @@ +#!/bin/sh + diff --git a/tools/ioemu/patches/remove-pci-bridge-setup b/tools/ioemu/patches/remove-pci-bridge-setup new file mode 100644 index 0000000000..a4f4c80b80 --- /dev/null +++ b/tools/ioemu/patches/remove-pci-bridge-setup @@ -0,0 +1,289 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID a8d31d5ce2589762c3226185deeca3afca47a698 +# Parent b8cc9ffda0a3dc449b026c72c97f78dea2e6f114 +[HVM] Move PCI and PCI-ISA bridge setup to hvmloader. +Signed-off-by: Keir Fraser + +Index: ioemu/target-i386-dm/piix_pci-dm.c +=================================================================== +--- ioemu.orig/target-i386-dm/piix_pci-dm.c 2006-12-08 18:22:35.000000000 +0000 ++++ ioemu/target-i386-dm/piix_pci-dm.c 2006-12-08 18:22:50.000000000 +0000 +@@ -84,12 +84,6 @@ + + static PCIDevice *piix3_dev; + +-static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num) +-{ +- /* This is the barber's pole mapping used by Xen. */ +- return (irq_num + (pci_dev->devfn >> 3)) & 3; +-} +- + static void piix3_write_config(PCIDevice *d, + uint32_t address, uint32_t val, int len) + { +@@ -114,12 +108,9 @@ + uint8_t *pci_conf = d->config; + + pci_conf[0x04] = 0x07; // master, memory and I/O +- pci_conf[0x05] = 0x00; +- pci_conf[0x06] = 0x00; + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; +- pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x61] = 0x80; + pci_conf[0x62] = 0x80; +@@ -129,22 +120,9 @@ + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; +- pci_conf[0x79] = 0x00; +- pci_conf[0x80] = 0x00; +- pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa0] = 0x08; +- pci_conf[0xa2] = 0x00; +- pci_conf[0xa3] = 0x00; +- pci_conf[0xa4] = 0x00; +- pci_conf[0xa5] = 0x00; +- pci_conf[0xa6] = 0x00; +- pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; +- pci_conf[0xaa] = 0x00; +- pci_conf[0xab] = 0x00; +- pci_conf[0xac] = 0x00; +- pci_conf[0xae] = 0x00; + } + + int piix3_init(PCIBus *bus) +@@ -171,227 +149,4 @@ + return d->devfn; + } + +-/***********************************************************/ +-/* XXX: the following should be moved to the PC BIOS */ +- +-static __attribute__((unused)) uint32_t isa_inb(uint32_t addr) +-{ +- return cpu_inb(NULL, addr); +-} +- +-static void isa_outb(uint32_t val, uint32_t addr) +-{ +- cpu_outb(NULL, addr, val); +-} +- +-static __attribute__((unused)) uint32_t isa_inw(uint32_t addr) +-{ +- return cpu_inw(NULL, addr); +-} +- +-static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr) +-{ +- cpu_outw(NULL, addr, val); +-} +- +-static __attribute__((unused)) uint32_t isa_inl(uint32_t addr) +-{ +- return cpu_inl(NULL, addr); +-} +- +-static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr) +-{ +- cpu_outl(NULL, addr, val); +-} +- +-static uint32_t pci_bios_io_addr; +-static uint32_t pci_bios_mem_addr; +-/* host irqs corresponding to PCI irqs A-D */ +-static uint8_t pci_irqs[4] = { 10, 11, 10, 11 }; +- +-static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val) +-{ +- PCIBus *s = d->bus; +- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); +- pci_data_write(s, addr, val, 4); +-} +- +-static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val) +-{ +- PCIBus *s = d->bus; +- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); +- pci_data_write(s, addr, val, 2); +-} +- +-static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val) +-{ +- PCIBus *s = d->bus; +- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); +- pci_data_write(s, addr, val, 1); +-} +- +-static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr) +-{ +- PCIBus *s = d->bus; +- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); +- return pci_data_read(s, addr, 4); +-} +- +-static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr) +-{ +- PCIBus *s = d->bus; +- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); +- return pci_data_read(s, addr, 2); +-} +- +-static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr) +-{ +- PCIBus *s = d->bus; +- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8); +- return pci_data_read(s, addr, 1); +-} +- +-static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) +-{ +- PCIIORegion *r; +- uint16_t cmd; +- uint32_t ofs; +- +- if ( region_num == PCI_ROM_SLOT ) { +- ofs = 0x30; +- }else{ +- ofs = 0x10 + region_num * 4; +- } +- +- pci_config_writel(d, ofs, addr); +- r = &d->io_regions[region_num]; +- +- /* enable memory mappings */ +- cmd = pci_config_readw(d, PCI_COMMAND); +- if ( region_num == PCI_ROM_SLOT ) +- cmd |= 2; +- else if (r->type & PCI_ADDRESS_SPACE_IO) +- cmd |= 1; +- else +- cmd |= 2; +- pci_config_writew(d, PCI_COMMAND, cmd); +-} +- +-static void pci_bios_init_device(PCIDevice *d) +-{ +- int class; +- PCIIORegion *r; +- uint32_t *paddr; +- int i, pin, pic_irq, vendor_id, device_id; +- +- class = pci_config_readw(d, PCI_CLASS_DEVICE); +- vendor_id = pci_config_readw(d, PCI_VENDOR_ID); +- device_id = pci_config_readw(d, PCI_DEVICE_ID); +- switch(class) { +- case 0x0101: +- if (vendor_id == 0x8086 && device_id == 0x7010) { +- /* PIIX3 IDE */ +- pci_config_writew(d, 0x40, 0x8000); // enable IDE0 +- pci_config_writew(d, 0x42, 0x8000); // enable IDE1 +- goto default_map; +- } else { +- /* IDE: we map it as in ISA mode */ +- pci_set_io_region_addr(d, 0, 0x1f0); +- pci_set_io_region_addr(d, 1, 0x3f4); +- pci_set_io_region_addr(d, 2, 0x170); +- pci_set_io_region_addr(d, 3, 0x374); +- } +- break; +- case 0x0680: +- if (vendor_id == 0x8086 && device_id == 0x7113) { +- /* +- * PIIX4 ACPI PM. +- * Special device with special PCI config space. No ordinary BARs. +- */ +- pci_config_writew(d, 0x20, 0x0000); // No smb bus IO enable +- pci_config_writew(d, 0x22, 0x0000); +- pci_config_writew(d, 0x3c, 0x0009); // Hardcoded IRQ9 +- pci_config_writew(d, 0x3d, 0x0001); +- } +- break; +- case 0x0300: +- if (vendor_id != 0x1234) +- goto default_map; +- /* VGA: map frame buffer to default Bochs VBE address */ +- pci_set_io_region_addr(d, 0, 0xE0000000); +- break; +- case 0x0800: +- /* PIC */ +- vendor_id = pci_config_readw(d, PCI_VENDOR_ID); +- device_id = pci_config_readw(d, PCI_DEVICE_ID); +- if (vendor_id == 0x1014) { +- /* IBM */ +- if (device_id == 0x0046 || device_id == 0xFFFF) { +- /* MPIC & MPIC2 */ +- pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000); +- } +- } +- break; +- case 0xff00: +- if (vendor_id == 0x0106b && +- (device_id == 0x0017 || device_id == 0x0022)) { +- /* macio bridge */ +- pci_set_io_region_addr(d, 0, 0x80800000); +- } +- break; +- default: +- default_map: +- /* default memory mappings */ +- for(i = 0; i < PCI_NUM_REGIONS; i++) { +- r = &d->io_regions[i]; +- if (r->size) { +- if (r->type & PCI_ADDRESS_SPACE_IO) +- paddr = &pci_bios_io_addr; +- else +- paddr = &pci_bios_mem_addr; +- *paddr = (*paddr + r->size - 1) & ~(r->size - 1); +- pci_set_io_region_addr(d, i, *paddr); +- *paddr += r->size; +- } +- } +- break; +- } +- +- /* map the interrupt */ +- pin = pci_config_readb(d, PCI_INTERRUPT_PIN); +- if (pin != 0) { +- pin = pci_slot_get_pirq(d, pin - 1); +- pic_irq = pci_irqs[pin]; +- pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq); +- } +-} +- +-/* +- * This function initializes the PCI devices as a normal PCI BIOS +- * would do. It is provided just in case the BIOS has no support for +- * PCI. +- */ +-void pci_bios_init(void) +-{ +- int i, irq; +- uint8_t elcr[2]; +- +- pci_bios_io_addr = 0xc000; +- pci_bios_mem_addr = HVM_BELOW_4G_MMIO_START; +- +- /* activate IRQ mappings */ +- elcr[0] = 0x00; +- elcr[1] = 0x00; +- for(i = 0; i < 4; i++) { +- irq = pci_irqs[i]; +- /* set to trigger level */ +- elcr[irq >> 3] |= (1 << (irq & 7)); +- /* activate irq remapping in PIIX */ +- pci_config_writeb(piix3_dev, 0x60 + i, irq); +- } +- isa_outb(elcr[0], 0x4d0); +- isa_outb(elcr[1], 0x4d1); +- +- pci_for_each_device(pci_bios_init_device); +-} +- ++void pci_bios_init(void) {} diff --git a/tools/ioemu/patches/rtl8139-bound-chaining b/tools/ioemu/patches/rtl8139-bound-chaining new file mode 100644 index 0000000000..a360ddbc49 --- /dev/null +++ b/tools/ioemu/patches/rtl8139-bound-chaining @@ -0,0 +1,36 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID 075f4ffdbbce5527ba525a515abe320703d17a0e +# Parent 51edd3c6a4d861db6ce1c9a02251ed49213c3002 +[QEMU] rtl8139: Disallow chaining above 64K + +As it stands the 8139C+ TX chaining is only bounded by realloc failure. +This is contrary to how the real hardware operates. It also has DoS +potential when ioemu runs in dom0. + +This patch makes any attempt to chain a frame beyond 64K fail +immediately. + +Signed-off-by: Herbert Xu + +Index: ioemu/hw/rtl8139.c +=================================================================== +--- ioemu.orig/hw/rtl8139.c 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/hw/rtl8139.c 2006-12-08 18:22:22.000000000 +0000 +@@ -1999,12 +1999,12 @@ + DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len)); + } + +- while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) ++ if (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len) + { +- s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE; +- s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len); ++ free(s->cplus_txbuffer); ++ s->cplus_txbuffer = NULL; + +- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len)); ++ DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space exceeded: %d\n", s->cplus_txbuffer_offset + txsize)); + } + + if (!s->cplus_txbuffer) diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index f6459c2139..0b92ba302f 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -53,3 +53,17 @@ serial-port-rate-limit hypervisor-rtc ide-cd-dma vnc-password +ne2000-bounds-checks +xenstore-device-info-functions +tpm-tis-device +qemu-serial-fixes +vnc-japan-keymap +rtl8139-bound-chaining +fix-interrupt-routing +nodelay-serial-over-tcp +remove-pci-bridge-setup +limit-fdc-sector-size-to-16K +usb-uhci-buffer-size +vnc-monitor-shift-key-processing +ide-error-reporting +vnc-numpad-handling diff --git a/tools/ioemu/patches/shared-vram b/tools/ioemu/patches/shared-vram index a3aa12aa5d..aa67a1ae8c 100644 --- a/tools/ioemu/patches/shared-vram +++ b/tools/ioemu/patches/shared-vram @@ -1,7 +1,7 @@ Index: ioemu/hw/cirrus_vga.c =================================================================== ---- ioemu.orig/hw/cirrus_vga.c 2006-08-17 19:37:36.372522620 +0100 -+++ ioemu/hw/cirrus_vga.c 2006-08-17 19:49:52.157002909 +0100 +--- ioemu.orig/hw/cirrus_vga.c 2006-12-08 01:57:54.000000000 +0000 ++++ ioemu/hw/cirrus_vga.c 2006-12-08 02:00:04.000000000 +0000 @@ -28,6 +28,9 @@ */ #include "vl.h" @@ -176,8 +176,8 @@ Index: ioemu/hw/cirrus_vga.c } Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-17 19:49:50.229215988 +0100 -+++ ioemu/hw/pc.c 2006-08-17 19:49:52.158002799 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 02:00:04.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 02:00:04.000000000 +0000 @@ -790,14 +790,14 @@ if (cirrus_vga_enabled) { if (pci_enabled) { @@ -198,8 +198,8 @@ Index: ioemu/hw/pc.c Index: ioemu/hw/vga.c =================================================================== ---- ioemu.orig/hw/vga.c 2006-08-17 19:49:37.764593706 +0100 -+++ ioemu/hw/vga.c 2006-08-17 19:49:52.159002688 +0100 +--- ioemu.orig/hw/vga.c 2006-12-08 02:00:04.000000000 +0000 ++++ ioemu/hw/vga.c 2006-12-08 02:00:04.000000000 +0000 @@ -1858,6 +1858,7 @@ /* TODO: add vbe support if enabled */ } @@ -251,8 +251,8 @@ Index: ioemu/hw/vga.c Index: ioemu/hw/vga_int.h =================================================================== ---- ioemu.orig/hw/vga_int.h 2006-08-17 19:37:36.372522620 +0100 -+++ ioemu/hw/vga_int.h 2006-08-17 19:49:52.159002688 +0100 +--- ioemu.orig/hw/vga_int.h 2006-12-08 01:57:54.000000000 +0000 ++++ ioemu/hw/vga_int.h 2006-12-08 02:00:04.000000000 +0000 @@ -169,5 +169,6 @@ unsigned int color0, unsigned int color1, unsigned int color_xor); @@ -262,9 +262,9 @@ Index: ioemu/hw/vga_int.h extern const uint8_t gr_mask[16]; Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-17 19:49:50.231215767 +0100 -+++ ioemu/vl.c 2006-08-17 19:49:52.162002356 +0100 -@@ -5693,6 +5693,78 @@ +--- ioemu.orig/vl.c 2006-12-08 02:00:04.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:00:27.000000000 +0000 +@@ -5693,6 +5693,62 @@ #define MAX_NET_CLIENTS 32 @@ -303,9 +303,6 @@ Index: ioemu/vl.c + unsigned long nr_pages, unsigned int address_bits, + xen_pfn_t *extent_start) +{ -+#if 0 -+ int i; -+#endif + xc_dominfo_t info; + int err = 0; + @@ -324,19 +321,6 @@ Index: ioemu/vl.c + return -1; + } + -+ err = xc_domain_translate_gpfn_list(xc_handle, domid, nr_pages, -+ extent_start, extent_start); -+ if (err) { -+ fprintf(stderr, "Failed to translate gpfn list\n"); -+ return -1; -+ } -+ -+#if 0 /* Generates lots of log file output - turn on for debugging */ -+ for (i = 0; i < nr_pages; i++) -+ fprintf(stderr, "set_map result i %x result %lx\n", i, -+ extent_start[i]); -+#endif -+ + return 0; +} + @@ -345,8 +329,8 @@ Index: ioemu/vl.c #ifdef CONFIG_GDBSTUB Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-17 19:49:44.492850031 +0100 -+++ ioemu/vl.h 2006-08-17 19:49:52.163002246 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:00:04.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:00:04.000000000 +0000 @@ -145,6 +145,13 @@ void main_loop_wait(int timeout); diff --git a/tools/ioemu/patches/tpm-tis-device b/tools/ioemu/patches/tpm-tis-device new file mode 100644 index 0000000000..5b5acc7b92 --- /dev/null +++ b/tools/ioemu/patches/tpm-tis-device @@ -0,0 +1,1182 @@ +# HG changeset patch +# User kaf24@localhost.localdomain +# Node ID d60b709724f48397b95da3d56299213cae391789 +# Parent bbcac2aea0e8196cd75a3bf6dbe57bebf8c1e5b2 +[QEMU] Add a TIS device model compliant to the 1.2 TPM specification. +It implements all registers necessary to make the Linux TIS driver +work (tpm_tis.c). All of the basic registers supported by this type of +device are implemented. Also the locality selection has been +implemented, but has not been tested. The legacy registers as +described in the specification are not supported. + +Current caveat: The device has so far not yet been integrated with the +virtual TPM available in the repository. It will require changes to +the virtual TPM spawned by the vTPM manager to offer an additional message +interface. The TIS interface itself then needs to have an additional +transport implemented. (see vTPMTransmit array). + +The relevant specification for the device model can be found here: +https://www.trustedcomputinggroup.org/groups/pc_client/TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf + +Signed-off-by: Stefan Berger + +Index: ioemu/Makefile.target +=================================================================== +--- ioemu.orig/Makefile.target 2006-12-08 18:20:53.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 18:21:18.000000000 +0000 +@@ -369,6 +369,7 @@ + VL_OBJS+= piix4acpi.o + VL_OBJS+= xenstore.o + VL_OBJS+= xen_platform.o ++VL_OBJS+= tpm_tis.o + DEFINES += -DHAS_AUDIO + endif + ifeq ($(TARGET_BASE_ARCH), ppc) +Index: ioemu/hw/pc.c +=================================================================== +--- ioemu.orig/hw/pc.c 2006-12-08 18:20:52.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 18:21:18.000000000 +0000 +@@ -875,6 +875,9 @@ + } + } + ++ if (has_tpm_device()) ++ tpm_tis_init(&pic_set_irq_new, isa_pic, 11); ++ + kbd_init(); + DMA_init(0); + #ifdef HAS_AUDIO +Index: ioemu/hw/tpm_tis.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/hw/tpm_tis.c 2006-12-08 18:21:18.000000000 +0000 +@@ -0,0 +1,1114 @@ ++/* ++ * tpm_tis.c - QEMU emulator for a 1.2 TPM with TIS interface ++ * ++ * Copyright (C) 2006 IBM Corporation ++ * ++ * Author: Stefan Berger ++ * David Safford ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation, version 2 of the ++ * License. ++ * ++ * ++ * Implementation of the TIS interface according to specs at ++ * https://www.trustedcomputinggroup.org/groups/pc_client/TCG_PCClientTPMSpecification_1-20_1-00_FINAL.pdf ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "vl.h" ++ ++//#define DEBUG_TPM ++ ++#define TPM_MAX_PKT 4096 ++ ++#define VTPM_BAD_INSTANCE (uint32_t)0xffffffff ++ ++#define TIS_ADDR_BASE 0xFED40000 ++ ++/* tis registers */ ++#define TPM_REG_ACCESS 0x00 ++#define TPM_REG_INT_ENABLE 0x08 ++#define TPM_REG_INT_VECTOR 0x0c ++#define TPM_REG_INT_STATUS 0x10 ++#define TPM_REG_INTF_CAPABILITY 0x14 ++#define TPM_REG_STS 0x18 ++#define TPM_REG_DATA_FIFO 0x24 ++#define TPM_REG_DID_VID 0xf00 ++#define TPM_REG_RID 0xf04 ++ ++#define STS_VALID (1 << 7) ++#define STS_COMMAND_READY (1 << 6) ++#define STS_TPM_GO (1 << 5) ++#define STS_DATA_AVAILABLE (1 << 4) ++#define STS_EXPECT (1 << 3) ++#define STS_RESPONSE_RETRY (1 << 1) ++ ++#define ACCESS_TPM_REG_VALID_STS (1 << 7) ++#define ACCESS_ACTIVE_LOCALITY (1 << 5) ++#define ACCESS_BEEN_SEIZED (1 << 4) ++#define ACCESS_SEIZE (1 << 3) ++#define ACCESS_PENDING_REQUEST (1 << 2) ++#define ACCESS_REQUEST_USE (1 << 1) ++#define ACCESS_TPM_ESTABLISHMENT (1 << 0) ++ ++#define INT_ENABLED (1 << 31) ++#define INT_DATA_AVAILABLE (1 << 0) ++#define INT_LOCALITY_CHANGED (1 << 2) ++#define INT_COMMAND_READY (1 << 7) ++ ++#define INTERRUPTS_SUPPORTED (INT_LOCALITY_CHANGED | \ ++ INT_DATA_AVAILABLE | \ ++ INT_COMMAND_READY) ++#define CAPABILITIES_SUPPORTED ((1 << 4) | \ ++ INTERRUPTS_SUPPORTED) ++ ++enum { ++ STATE_IDLE = 0, ++ STATE_READY, ++ STATE_COMPLETION, ++ STATE_EXECUTION, ++ STATE_RECEPTION ++}; ++ ++#define NUM_LOCALITIES 5 ++#define NO_LOCALITY 0xff ++ ++#define IS_VALID_LOC(x) ((x) < NUM_LOCALITIES) ++ ++#define TPM_DID 0x0001 ++#define TPM_VID 0x0001 ++#define TPM_RID 0x0001 ++ ++/* if the connection to the vTPM should be closed after a successfully ++ received response; set to '0' to allow keeping the connection */ ++#define FORCE_CLOSE 0 ++ ++/* local data structures */ ++ ++typedef struct TPMTx { ++ int fd[2]; ++} tpmTx; ++ ++typedef struct TPMBuffer { ++ uint8_t instance[4]; /* instance number in network byte order */ ++ uint8_t buf[TPM_MAX_PKT]; ++} __attribute__((packed)) tpmBuffer; ++ ++/* locality data */ ++typedef struct TPMLocal { ++ uint32_t state; ++ uint8_t access; ++ uint8_t sts; ++ uint32_t inte; ++ uint32_t ints; ++} tpmLoc; ++ ++/* overall state of the TPM interface; 's' marks as save upon suspension */ ++typedef struct TPMState { ++ uint32_t offset; /* s */ ++ tpmBuffer buffer; /* s */ ++ uint8_t active_loc; /* s */ ++ uint8_t aborting_locty; ++ uint8_t next_locty; ++ uint8_t irq_pending; /* s */ ++ tpmLoc loc[NUM_LOCALITIES]; /* s */ ++ QEMUTimer *poll_timer; ++ SetIRQFunc *set_irq; ++ void *irq_opaque; ++ int irq; ++ int poll_attempts; ++ uint32_t vtpm_instance; /* vtpm inst. number; determined from xenstore*/ ++ int Transmitlayer; ++ tpmTx tpmTx; ++} tpmState; ++ ++ ++/* local prototypes */ ++static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg); ++static int TPM_Receive(tpmState *s, tpmBuffer *buffer); ++static uint32_t vtpm_instance_from_xenstore(void); ++static void tis_poll_timer(void *opaque); ++static void tis_prep_next_interrupt(tpmState *s); ++static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask); ++static void close_vtpm_channel(tpmState *s, int force); ++static void open_vtpm_channel(tpmState *s); ++static void tis_attempt_receive(tpmState *s, uint8_t locty); ++ ++/* transport layer functions: local sockets */ ++static int create_local_socket(tpmState *s, uint32_t vtpm_instance); ++static int write_local_socket(tpmState *s, const tpmBuffer *); ++static int read_local_socket(tpmState *s, tpmBuffer *); ++static int close_local_socket(tpmState *s, int force); ++static int has_channel_local_socket(tpmState *s); ++#define LOCAL_SOCKET_PATH "/var/vtpm/vtpm_all.socket" ++ ++ ++#define NUM_TRANSPORTS 1 ++ ++struct vTPM_transmit { ++ int (*open) (tpmState *s, uint32_t vtpm_instance); ++ int (*write) (tpmState *s, const tpmBuffer *); ++ int (*read) (tpmState *s, tpmBuffer *); ++ int (*close) (tpmState *s, int); ++ int (*has_channel) (tpmState *s); ++} vTPMTransmit[NUM_TRANSPORTS] = { ++ { .open = create_local_socket, ++ .write = write_local_socket, ++ .read = read_local_socket, ++ .close = close_local_socket, ++ .has_channel = has_channel_local_socket, ++ } ++}; ++ ++ ++#define IS_COMM_WITH_VTPM(s) \ ++ ((s)->Transmitlayer >= 0 && \ ++ vTPMTransmit[(s)->Transmitlayer].has_channel(s)) ++ ++ ++/********************************************************************** ++ helper functions ++ *********************************************************************/ ++ ++static inline uint32_t tpm_get_size_from_buffer(const uint8_t *buffer) ++{ ++ uint32_t len = (buffer[4] << 8) + buffer[5]; ++ return len; ++} ++ ++static inline void tpm_initialize_instance(tpmState *s, uint32_t instance) ++{ ++ s->buffer.instance[0] = (instance >> 24) & 0xff; ++ s->buffer.instance[1] = (instance >> 16) & 0xff; ++ s->buffer.instance[2] = (instance >> 8) & 0xff; ++ s->buffer.instance[3] = (instance >> 0) & 0xff; ++} ++ ++/* ++ * open communication channel with a vTPM ++ */ ++static void open_vtpm_channel(tpmState *s) ++{ ++ int idx; ++ /* search a usable transmit layer */ ++ for (idx = 0; idx < NUM_TRANSPORTS; idx++) { ++ if (1 == vTPMTransmit[idx].open(s, s->vtpm_instance)) { ++ /* found one */ ++ s->Transmitlayer = idx; ++ break; ++ } ++ } ++} ++ ++/* ++ * close the communication channel with the vTPM ++ */ ++static inline void close_vtpm_channel(tpmState *s, int force) ++{ ++ if (1 == vTPMTransmit[s->Transmitlayer].close(s, force)) { ++ s->Transmitlayer = -1; ++ } ++} ++ ++static inline uint8_t locality_from_addr(target_phys_addr_t addr) ++{ ++ return (uint8_t)((addr >> 12) & 0x7); ++} ++ ++ ++/********************************************************************** ++ low-level transmission layer methods ++ *********************************************************************/ ++ ++/* ++ * the 'open' method that creates the filedescriptor for communicating ++ * only one is needed for reading and writing ++ */ ++static int create_local_socket(tpmState *s, uint32_t vtpm_instance) ++{ ++ int success = 1; ++ if (s->tpmTx.fd[0] < 0) { ++ s->tpmTx.fd[0] = socket(PF_LOCAL, SOCK_STREAM, 0); ++ ++ if (has_channel_local_socket(s)) { ++ struct sockaddr_un addr; ++ memset(&addr, 0x0, sizeof(addr)); ++ addr.sun_family = AF_LOCAL; ++ strcpy(addr.sun_path, LOCAL_SOCKET_PATH); ++ if (connect(s->tpmTx.fd[0], ++ (struct sockaddr *)&addr, ++ sizeof(addr)) != 0) { ++ close_local_socket(s, 1); ++ success = 0; ++ } else { ++ /* put filedescriptor in non-blocking mode for polling */ ++ int flags = fcntl(s->tpmTx.fd[0], F_GETFL); ++ fcntl(s->tpmTx.fd[0], F_SETFL, flags | O_NONBLOCK); ++ } ++#ifdef DEBUG_TPM ++ if (success) ++ fprintf(logfile,"Successfully connected using local socket " ++ LOCAL_SOCKET_PATH ".\n"); ++ else ++ fprintf(logfile,"Could not connect to local socket " ++ LOCAL_SOCKET_PATH ".\n"); ++#endif ++ } else { ++ success = 0; ++ } ++ } ++ return success; ++} ++ ++/* ++ * the 'write' method for sending requests to the vTPM ++ * four bytes with the vTPM instance number are prepended to each request ++ */ ++static int write_local_socket(tpmState *s, const tpmBuffer *buffer) ++{ ++ uint32_t size = tpm_get_size_from_buffer(buffer->buf); ++ int len; ++ ++ len = write(s->tpmTx.fd[0], ++ buffer->instance, ++ sizeof(buffer->instance) + size); ++ if (len == sizeof(buffer->instance) + size) { ++ return len; ++ } else { ++ return -1; ++ } ++} ++ ++/* ++ * the 'read' method for receiving of responses from the TPM ++ * this function expects that four bytes with the instance number ++ * are received from the vTPM ++ */ ++static int read_local_socket(tpmState *s, tpmBuffer *buffer) ++{ ++ int off; ++#ifdef DEBUG_TPM ++ fprintf(logfile, "Reading from fd %d\n", s->tpmTx.fd[0]); ++#endif ++ off = read(s->tpmTx.fd[0], ++ buffer->instance, ++ sizeof(buffer->instance)+TPM_MAX_PKT); ++#ifdef DEBUG_TPM ++ fprintf(logfile, "Read %d bytes\n", off); ++#endif ++ return off; ++} ++ ++/* ++ * the 'close' method ++ * shut down communication with the vTPM ++ * 'force' = 1 indicates that the socket *must* be closed ++ * 'force' = 0 indicates that a connection may be maintained ++ */ ++static int close_local_socket(tpmState *s, int force) ++{ ++ if (force) { ++ close(s->tpmTx.fd[0]); ++#ifdef DEBUG_TPM ++ fprintf(logfile,"Closed connection with fd %d\n",s->tpmTx.fd[0]); ++#endif ++ s->tpmTx.fd[0] = -1; ++ return 1; /* socket was closed */ ++ } ++#ifdef DEBUG_TPM ++ fprintf(logfile,"Keeping connection with fd %d\n",s->tpmTx.fd[0]); ++#endif ++ return 0; ++} ++ ++/* ++ * the 'has_channel' method that checks whether there's a communication ++ * channel with the vTPM ++ */ ++static int has_channel_local_socket(tpmState *s) ++{ ++ return (s->tpmTx.fd[0] > 0); ++} ++ ++/**********************************************************************/ ++ ++/* ++ * read a byte of response data ++ */ ++static uint32_t tpm_data_read(tpmState *s, uint8_t locty) ++{ ++ uint32_t ret, len; ++ ++ /* try to receive data, if none are there it is ok */ ++ tis_attempt_receive(s, locty); ++ ++ if (s->loc[locty].state != STATE_COMPLETION) { ++ return 0xff; ++ } ++ ++ len = tpm_get_size_from_buffer(s->buffer.buf); ++ ret = s->buffer.buf[s->offset++]; ++ if (s->offset >= len) { ++ s->loc[locty].sts = STS_VALID ; ++ s->offset = 0; ++ } ++#ifdef DEBUG_TPM ++ fprintf(logfile,"tpm_data_read byte x%02x [%d]\n",ret,s->offset-1); ++#endif ++ return ret; ++} ++ ++ ++ ++/* raise an interrupt if allowed */ ++static void tis_raise_irq(tpmState *s, uint8_t locty, uint32_t irqmask) ++{ ++ if (!s->irq_pending && ++ (s->loc[locty].inte & INT_ENABLED) && ++ (s->loc[locty].inte & irqmask)) { ++ if ((irqmask & s->loc[locty].ints) == 0) { ++#ifdef DEBUG_TPM ++ fprintf(logfile,"Raising IRQ for flag %08x\n",irqmask); ++#endif ++ s->set_irq(s->irq_opaque, s->irq, 1); ++ s->irq_pending = 1; ++ s->loc[locty].ints |= irqmask; ++ } ++ } ++} ++ ++/* abort execution of command */ ++static void tis_abort(tpmState *s) ++{ ++ s->offset = 0; ++ s->active_loc = s->next_locty; ++ ++ /* ++ * Need to react differently depending on who's aborting now and ++ * which locality will become active afterwards. ++ */ ++ if (s->aborting_locty == s->next_locty) { ++ s->loc[s->aborting_locty].state = STATE_READY; ++ s->loc[s->aborting_locty].sts = STS_COMMAND_READY; ++ tis_raise_irq(s, s->aborting_locty, INT_COMMAND_READY); ++ } ++ ++ /* locality after abort is another one than the current one */ ++ if (s->aborting_locty != s->next_locty && s->next_locty != NO_LOCALITY) { ++ s->loc[s->aborting_locty].access &= ~ACCESS_ACTIVE_LOCALITY; ++ s->loc[s->next_locty].access |= ACCESS_ACTIVE_LOCALITY; ++ tis_raise_irq(s, s->next_locty, INT_LOCALITY_CHANGED); ++ } ++ ++ s->aborting_locty = NO_LOCALITY; /* nobody's aborting a command anymore */ ++ ++ qemu_del_timer(s->poll_timer); ++} ++ ++/* abort current command */ ++static void tis_prep_abort(tpmState *s, uint8_t locty, uint8_t newlocty) ++{ ++ s->aborting_locty = locty; /* current locality */ ++ s->next_locty = newlocty; /* locality after successful abort */ ++ ++ /* ++ * only abort a command using an interrupt if currently executing ++ * a command AND if there's a valid connection to the vTPM. ++ */ ++ if (s->loc[locty].state == STATE_EXECUTION && ++ IS_COMM_WITH_VTPM(s)) { ++ /* start timer and inside the timer wait for the result */ ++ s->poll_attempts = 0; ++ tis_prep_next_interrupt(s); ++ } else { ++ tis_abort(s); ++ } ++} ++ ++ ++/* ++ * Try to receive a response from the vTPM ++ */ ++static void tis_attempt_receive(tpmState *s, uint8_t locty) ++{ ++ /* ++ * Attempt to read from the vTPM here if ++ * - not aborting a command ++ * - command has been sent and state is 'EXECUTION' now ++ * - no data are already available (data have already been read) ++ * - there's a communication path to the vTPM established ++ */ ++ if (!IS_VALID_LOC(s->aborting_locty)) { ++ if (s->loc[locty].state == STATE_EXECUTION) { ++ if (0 == (s->loc[locty].sts & STS_DATA_AVAILABLE)){ ++ if (IS_COMM_WITH_VTPM(s)) { ++ int n = TPM_Receive(s, &s->buffer); ++ if (n > 0) { ++ s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE; ++ s->loc[locty].state = STATE_COMPLETION; ++ close_vtpm_channel(s, FORCE_CLOSE); ++ tis_raise_irq(s, locty, INT_DATA_AVAILABLE); ++ } ++ } ++ } ++ } ++ } ++} ++ ++/* ++ * Read a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static uint32_t tis_mem_readl(void *opaque, target_phys_addr_t addr) ++{ ++ tpmState *s = (tpmState *)opaque; ++ uint16_t offset = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint32_t val = 0; ++ uint8_t locty = locality_from_addr(addr); ++ ++ if (offset == TPM_REG_ACCESS) { ++ if (s->active_loc == locty) { ++ s->loc[locty].access |= (1 << 5); ++ } else { ++ s->loc[locty].access &= ~(1 << 5); ++ } ++ val = s->loc[locty].access; ++ } else ++ if (offset == TPM_REG_INT_ENABLE) { ++ val = s->loc[locty].inte; ++ } else ++ if (offset == TPM_REG_INT_VECTOR) { ++ val = s->irq; ++ } else ++ if (offset == TPM_REG_INT_STATUS) { ++ tis_attempt_receive(s, locty); ++ val = s->loc[locty].ints; ++ } else ++ if (offset == TPM_REG_INTF_CAPABILITY) { ++ val = CAPABILITIES_SUPPORTED; ++ } else ++ if (offset == TPM_REG_STS) { /* status register */ ++ tis_attempt_receive(s, locty); ++ val = (sizeof(s->buffer.buf) - s->offset) << 8 | s->loc[locty].sts; ++ } else ++ if (offset == TPM_REG_DATA_FIFO) { ++ val = tpm_data_read(s, locty); ++ } else ++ if (offset == TPM_REG_DID_VID) { ++ val = (TPM_DID << 16) | TPM_VID; ++ } else ++ if (offset == TPM_REG_RID) { ++ val = TPM_RID; ++ } ++ ++ if (shift) ++ val >>= shift; ++ ++#ifdef DEBUG_TPM ++ fprintf(logfile," read(%08x) = %08x\n", ++ addr, ++ val); ++#endif ++ ++ return val; ++} ++ ++/* ++ * Write a value to a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static void tis_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) ++{ ++ tpmState* s=(tpmState*)opaque; ++ uint16_t off = addr & 0xfff; ++ uint8_t locty = locality_from_addr(addr); ++ int n, c; ++ uint32_t len; ++ ++#ifdef DEBUG_TPM ++ fprintf(logfile,"write(%08x) = %08x\n", ++ addr, ++ val); ++#endif ++ ++ if (off == TPM_REG_ACCESS) { ++ if (val & ACCESS_ACTIVE_LOCALITY) { ++ /* give up locality if currently owned */ ++ if (s->active_loc == locty) { ++ uint8_t newlocty = NO_LOCALITY; ++ s->loc[locty].access &= ~(ACCESS_PENDING_REQUEST); ++ /* anybody wants the locality ? */ ++ for (c = NUM_LOCALITIES - 1; c >= 0; c--) { ++ if (s->loc[c].access & ACCESS_REQUEST_USE) { ++ s->loc[c].access |= ACCESS_TPM_REG_VALID_STS; ++ s->loc[c].access &= ~ACCESS_REQUEST_USE; ++ newlocty = c; ++ break; ++ } ++ } ++ tis_prep_abort(s, locty, newlocty); ++ } ++ } ++ if (val & ACCESS_BEEN_SEIZED) { ++ /* clear the flag */ ++ s->loc[locty].access &= ~ACCESS_BEEN_SEIZED; ++ } ++ if (val & ACCESS_SEIZE) { ++ if (locty > s->active_loc && IS_VALID_LOC(s->active_loc)) { ++ s->loc[s->active_loc].access |= ACCESS_BEEN_SEIZED; ++ s->loc[locty].access = ACCESS_TPM_REG_VALID_STS; ++ tis_prep_abort(s, s->active_loc, locty); ++ } ++ } ++ if (val & ACCESS_REQUEST_USE) { ++ if (IS_VALID_LOC(s->active_loc)) { ++ /* locality election */ ++ s->loc[s->active_loc].access |= ACCESS_PENDING_REQUEST; ++ } else { ++ /* no locality active -> make this one active now */ ++ s->loc[locty].access |= ACCESS_ACTIVE_LOCALITY; ++ s->active_loc = locty; ++ tis_raise_irq(s, locty, INT_LOCALITY_CHANGED); ++ } ++ } ++ } else ++ if (off == TPM_REG_INT_ENABLE) { ++ s->loc[locty].inte = (val & (INT_ENABLED | (0x3 << 3) | ++ INTERRUPTS_SUPPORTED)); ++ } else ++ if (off == TPM_REG_INT_STATUS) { ++ /* clearing of interrupt flags */ ++ if ((val & INTERRUPTS_SUPPORTED) && ++ (s->loc[locty].ints & INTERRUPTS_SUPPORTED)) { ++ s->set_irq(s->irq_opaque, s->irq, 0); ++ s->irq_pending = 0; ++ } ++ s->loc[locty].ints &= ~(val & INTERRUPTS_SUPPORTED); ++ } else ++ if (off == TPM_REG_STS) { ++ if (val & STS_COMMAND_READY) { ++ if (s->loc[locty].state == STATE_IDLE) { ++ s->loc[locty].sts = STS_COMMAND_READY; ++ s->loc[locty].state = STATE_READY; ++ tis_raise_irq(s, locty, INT_COMMAND_READY); ++ } else if (s->loc[locty].state == STATE_COMPLETION || ++ s->loc[locty].state == STATE_EXECUTION || ++ s->loc[locty].state == STATE_RECEPTION) { ++ /* abort currently running command */ ++ tis_prep_abort(s, locty, locty); ++ } ++ } ++ if (val & STS_TPM_GO) { ++ n = TPM_Send(s, &s->buffer,"tpm_data_write"); ++ if (n > 0) { ++ /* sending of data was successful */ ++ s->offset = 0; ++ s->loc[locty].state = STATE_EXECUTION; ++ if (s->loc[locty].inte & (INT_ENABLED | INT_DATA_AVAILABLE)) { ++ s->poll_attempts = 0; ++ tis_prep_next_interrupt(s); ++ } ++ } ++ } ++ if (val & STS_RESPONSE_RETRY) { ++ s->offset = 0; ++ } ++ } else if (off == TPM_REG_DATA_FIFO) { ++ /* data fifo */ ++ if (s->loc[locty].state == STATE_IDLE || ++ s->loc[locty].state == STATE_EXECUTION || ++ s->loc[locty].state == STATE_COMPLETION) { ++ /* drop the byte */ ++ } else { ++#ifdef TPM_DEBUG ++ fprintf(logfile,"Byte to send to TPM: %02x\n", val); ++#endif ++ s->loc[locty].state = STATE_RECEPTION; ++ ++ if (s->offset < sizeof(s->buffer.buf)) ++ s->buffer.buf[s->offset++] = (uint8_t)val; ++ ++ if (s->offset > 5) { ++ /* we have a packet length - see if we have all of it */ ++ len = tpm_get_size_from_buffer(s->buffer.buf); ++ if (len > s->offset) { ++ s->loc[locty].sts = STS_EXPECT | STS_VALID; ++ } else { ++ s->loc[locty].sts = STS_VALID; ++ } ++ } ++ } ++ } ++} ++ ++/* ++ * Prepare the next interrupt for example after a command has ++ * been sent out for the purpose of receiving the response. ++ * Depending on how many interrupts (used for polling on the fd) have ++ * already been schedule, this function determines the delta in time ++ * to the next interrupt. This accomodates for commands that finish ++ * quickly. ++ */ ++static void tis_prep_next_interrupt(tpmState *s) ++{ ++ int64_t expiration; ++ int rate = 5; /* 5 times per second */ ++ ++ /* ++ poll often at the beginning for quickly finished commands, ++ then back off ++ */ ++ if (s->poll_attempts < 5) { ++ rate = 20; ++ } else if (s->poll_attempts < 10) { ++ rate = 10; ++ } ++ ++ expiration = qemu_get_clock(vm_clock) + (ticks_per_sec / rate); ++ qemu_mod_timer(s->poll_timer, expiration); ++ s->poll_attempts++; ++} ++ ++ ++/* ++ * The polling routine called when the 'timer interrupt' fires. ++ * Tries to receive a command from the vTPM. ++ */ ++static void tis_poll_timer(void *opaque) ++{ ++ tpmState* s=(tpmState*)opaque; ++ uint8_t locty = s->active_loc; ++ ++ if (!IS_VALID_LOC(locty) || ++ (!(s->loc[locty].inte & INT_ENABLED) && ++ (s->aborting_locty != NO_LOCALITY)) || ++ !IS_COMM_WITH_VTPM(s)) { ++ /* no more interrupts requested, so no more polling needed */ ++ qemu_del_timer(s->poll_timer); ++ } ++ ++ if (!IS_COMM_WITH_VTPM(s)) { ++ if (s->aborting_locty != NO_LOCALITY) { ++ tis_abort(s); ++ } ++ return; ++ } ++ ++ if (s->aborting_locty != NO_LOCALITY) { ++ int n = TPM_Receive(s, &s->buffer); ++#ifdef DEBUG_TPM ++ fprintf(logfile,"Receiving for abort.\n"); ++#endif ++ if (n > 0) { ++ close_vtpm_channel(s, FORCE_CLOSE); ++ tis_abort(s); ++#ifdef DEBUG_TPM ++ fprintf(logfile,"Abort is complete.\n"); ++#endif ++ } else { ++ tis_prep_next_interrupt(s); ++ } ++ } else if (IS_VALID_LOC(locty)) { ++ if (s->loc[locty].state == STATE_EXECUTION) { ++ /* poll for result */ ++ int n = TPM_Receive(s, &s->buffer); ++ if (n > 0) { ++ s->loc[locty].sts = STS_VALID | STS_DATA_AVAILABLE; ++ s->loc[locty].state = STATE_COMPLETION; ++ close_vtpm_channel(s, FORCE_CLOSE); ++ tis_raise_irq(s, locty, INT_DATA_AVAILABLE); ++ } else { ++ /* nothing received */ ++ tis_prep_next_interrupt(s); ++ } ++ } ++ } ++} ++ ++ ++static CPUReadMemoryFunc *tis_readfn[3]={ ++ tis_mem_readl, ++ tis_mem_readl, ++ tis_mem_readl ++}; ++ ++static CPUWriteMemoryFunc *tis_writefn[3]={ ++ tis_mem_writel, ++ tis_mem_writel, ++ tis_mem_writel ++}; ++ ++/* ++ * Save the internal state of this interface for later resumption. ++ * Need to get any outstanding responses from the vTPM back, so ++ * this might delay the suspend for a while. ++ */ ++static void tpm_save(QEMUFile* f,void* opaque) ++{ ++ tpmState* s=(tpmState*)opaque; ++ int c; ++ ++ /* need to wait for outstanding requests to complete */ ++ if (IS_COMM_WITH_VTPM(s)) { ++ int repeats = 30; /* 30 seconds; really should be infty */ ++ while (repeats > 0 && ++ !(s->loc[s->active_loc].sts & STS_DATA_AVAILABLE)) { ++ int n = TPM_Receive(s, &s->buffer); ++ if (n > 0) { ++ if (IS_VALID_LOC(s->active_loc)) { ++ s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE; ++ } ++ /* close the connection with the vTPM for good */ ++ close_vtpm_channel(s, 1); ++ break; ++ } ++ sleep(1); ++ } ++ } ++ ++ qemu_put_be32s(f,&s->offset); ++ qemu_put_buffer(f, s->buffer.buf, TPM_MAX_PKT); ++ qemu_put_8s(f, &s->active_loc); ++ qemu_put_8s(f, &s->irq_pending); ++ for (c = 0; c < NUM_LOCALITIES; c++) { ++ qemu_put_be32s(f, &s->loc[c].state); ++ qemu_put_8s(f, &s->loc[c].access); ++ qemu_put_8s(f, &s->loc[c].sts); ++ qemu_put_be32s(f, &s->loc[c].inte); ++ qemu_put_be32s(f, &s->loc[c].ints); ++ } ++} ++ ++/* ++ * load TIS interface state ++ */ ++static int tpm_load(QEMUFile* f,void* opaque,int version_id) ++{ ++ tpmState* s=(tpmState*)opaque; ++ int c; ++ ++ if (version_id != 1) ++ return -EINVAL; ++ ++ qemu_get_be32s(f,&s->offset); ++ qemu_get_buffer(f, s->buffer.buf, TPM_MAX_PKT); ++ qemu_get_8s(f, &s->active_loc); ++ qemu_get_8s(f, &s->irq_pending); ++ for (c = 0; c < NUM_LOCALITIES; c++) { ++ qemu_get_be32s(f, &s->loc[c].state); ++ qemu_get_8s(f, &s->loc[c].access); ++ qemu_get_8s(f, &s->loc[c].sts); ++ qemu_get_be32s(f, &s->loc[c].inte); ++ qemu_get_be32s(f, &s->loc[c].ints); ++ } ++ ++ /* need to be able to get the instance number from the xenstore */ ++ s->vtpm_instance = vtpm_instance_from_xenstore(); ++ if (s->vtpm_instance == VTPM_BAD_INSTANCE) ++ return -EINVAL; ++ tpm_initialize_instance(s, s->vtpm_instance); ++ ++ return 0; ++} ++ ++ ++typedef struct LPCtpmState { ++ tpmState tpm; ++ int mem; ++} LPCtpmState; ++ ++ ++/* ++ * initialize TIS interface ++ */ ++void tpm_tis_init(SetIRQFunc *set_irq, void *opaque, int irq) ++{ ++ LPCtpmState *d; ++ tpmState *s; ++ int c = 0; ++ uint32_t vtpm_in; ++ ++ vtpm_in = vtpm_instance_from_xenstore(); ++ /* no valid vtpm instance -> no device */ ++ if (vtpm_in == VTPM_BAD_INSTANCE) ++ return; ++ ++ d = qemu_mallocz(sizeof(LPCtpmState)); ++ d->mem = cpu_register_io_memory(0, tis_readfn, tis_writefn, d); ++ ++ if (d->mem == -1) { ++ return; ++ } ++ ++ cpu_register_physical_memory(TIS_ADDR_BASE, ++ 0x1000 * NUM_LOCALITIES, d->mem); ++ ++ /* initialize tpmState */ ++ s = &d->tpm; ++ ++ s->offset = 0; ++ s->active_loc = NO_LOCALITY; ++ ++ while (c < NUM_LOCALITIES) { ++ s->loc[c].access = (1 << 7); ++ s->loc[c].sts = 0; ++ s->loc[c].inte = (1 << 3); ++ s->loc[c].ints = 0; ++ s->loc[c].state = STATE_IDLE; ++ c++; ++ } ++ s->poll_timer = qemu_new_timer(vm_clock, tis_poll_timer, s); ++ s->set_irq = set_irq; ++ s->irq_opaque = opaque; ++ s->irq = irq; ++ s->vtpm_instance = vtpm_in; ++ s->Transmitlayer = -1; ++ s->tpmTx.fd[0] = -1; ++ s->tpmTx.fd[1] = -1; ++ ++ tpm_initialize_instance(s, s->vtpm_instance); ++ memset(s->buffer.buf,0,sizeof(s->buffer.buf)); ++ ++ register_savevm("tpm-tis", 0, 1, tpm_save, tpm_load, s); ++} ++ ++/****************************************************************************/ ++/* optional verbose logging of data to/from vtpm */ ++/****************************************************************************/ ++#ifdef DEBUG_TPM ++static void showBuff(unsigned char *buff, char *string) ++{ ++ uint32_t i, len; ++ ++ len = tpm_get_size_from_buffer(buff); ++ fprintf(logfile,"%s length = %d\n", string, len); ++ for (i = 0; i < len; i++) { ++ if (i && !(i % 16)) { ++ fprintf(logfile,"\n"); ++ } ++ fprintf(logfile,"%.2X ", buff[i]); ++ } ++ fprintf(logfile,"\n"); ++} ++#endif ++ ++/****************************************************************************/ ++/* Transmit request to TPM and read Response */ ++/****************************************************************************/ ++ ++const static unsigned char tpm_failure[] = { ++ 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x0a, ++ 0x00, 0x00, 0x00, 0x09 ++}; ++ ++ ++/* ++ * Send a TPM request. ++ */ ++static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg) ++{ ++ int len; ++ uint32_t size = tpm_get_size_from_buffer(buffer->buf); ++ ++ /* try to establish a connection to the vTPM */ ++ if ( !IS_COMM_WITH_VTPM(s)) { ++ open_vtpm_channel(s); ++ } ++ ++ if ( !IS_COMM_WITH_VTPM(s)) { ++ unsigned char tag = buffer->buf[1]; ++ ++ /* there's a failure response from the TPM */ ++ memcpy(buffer->buf, tpm_failure, sizeof(tpm_failure)); ++ buffer->buf[1] = tag + 3; ++ if (IS_VALID_LOC(s->active_loc)) { ++ s->loc[s->active_loc].sts = STS_DATA_AVAILABLE | STS_VALID; ++ } ++#ifdef DEBUG_TPM ++ fprintf(logfile,"No TPM running!\n"); ++#endif ++ /* the request went out ok. */ ++ return sizeof(buffer->instance) + size; ++ } ++ ++#ifdef DEBUG_TPM ++ showBuff(buffer->buf, "To TPM"); ++#endif ++ ++ len = vTPMTransmit[s->Transmitlayer].write(s, buffer); ++ if (len < 0) { ++ s->Transmitlayer = -1; ++ } ++ return len; ++} ++ ++/* ++ * Try to receive data from the file descriptor. Since it is in ++ * non-blocking mode it is possible that no data are actually received - ++ * whatever calls this function needs to try again later. ++ */ ++static int TPM_Receive(tpmState *s, tpmBuffer *buffer) ++{ ++ int off; ++ ++ off = vTPMTransmit[s->Transmitlayer].read(s, buffer); ++ ++ if (off < 0) { ++ /* EAGAIN is set in errno due to non-blocking mode */ ++ return -1; ++ } ++ ++ if (off == 0) { ++#ifdef DEBUG_TPM ++ fprintf(logfile,"TPM GONE? errno=%d\n",errno); ++#endif ++ close_vtpm_channel(s, 1); ++ /* pretend that data are available */ ++ if (IS_VALID_LOC(s->active_loc)) { ++ s->loc[s->active_loc].sts = STS_VALID | STS_DATA_AVAILABLE; ++ s->loc[s->active_loc].state = STATE_COMPLETION; ++ tis_raise_irq(s, s->active_loc, INT_DATA_AVAILABLE); ++ } ++ return -1; ++ } ++ ++#ifdef DEBUG_TPM ++ if (off > sizeof(buffer->instance ) + 6) { ++ uint32_t size = tpm_get_size_from_buffer(buffer->buf); ++ if (size + sizeof(buffer->instance) != off) { ++ fprintf(logfile,"TPM: Packet size is bad! %d != %d\n", ++ size + sizeof(buffer->instance), ++ off); ++ } else { ++ uint32_t ret; ++ showBuff(buffer->buf, "From TPM"); ++ ret = (buffer->buf[8])*256 + buffer->buf[9]; ++ if (ret) ++ fprintf(logfile,"Receive failed with error %d\n", ret); ++ else ++ fprintf(logfile,"Receive succeeded. Got response of length %d (=%d)\n", ++ size, off); ++ } ++ } ++#endif ++ ++ /* assuming reading in one chunk for now */ ++ return off; ++} ++ ++ ++/**************************************************************************** ++ Helper functions for reading data from the xenstore such as ++ reading virtual TPM instance information ++ ****************************************************************************/ ++int has_tpm_device(void) ++{ ++ int ret = 0; ++ struct xs_handle *handle = xs_daemon_open(); ++ if (handle) { ++ ret = xenstore_domain_has_devtype(handle, "vtpm"); ++ xs_daemon_close(handle); ++ } ++ return ret; ++} ++ ++ ++/* ++ * Wait until hotplug scripts have finished then read the vTPM instance ++ * number from the xenstore. ++ */ ++static uint32_t vtpm_instance_from_xenstore(void) ++{ ++ unsigned int num; ++ uint32_t number = VTPM_BAD_INSTANCE; ++ int end = 0; ++ char *token = "tok"; ++ int subscribed = 0; ++ int ctr = 0; ++ fd_set readfds; ++ ++ struct xs_handle *handle = xs_daemon_open(); ++ ++ FD_ZERO(&readfds); ++ ++ if (handle) { ++ char **e = xenstore_domain_get_devices(handle, "vtpm", &num); ++ int fd = xs_fileno(handle); ++ FD_SET(fd, &readfds); ++ if (e) { ++ do { ++ struct timeval tv = { ++ .tv_sec = 30, ++ .tv_usec = 0, ++ }; ++ /* need to make sure that the hotplug scripts have finished */ ++ char *status = xenstore_read_hotplug_status(handle, ++ "vtpm", ++ e[0]); ++ if (status) { ++ if (!strcmp(status, "connected")) { ++ char *inst = xenstore_backend_read_variable(handle, ++ "vtpm", ++ e[0], ++ "instance"); ++ if (1 != (sscanf(inst,"%d",&number))) ++ number = VTPM_BAD_INSTANCE; ++ free(inst); ++ } else { ++ fprintf(logfile, ++ "bad status '%s' from vtpm hotplug\n", ++ status); ++ } ++ free(status); ++ end = 1; ++ } else { ++ /* no status, yet */ ++ int rc; ++ unsigned int nr; ++ char **f; ++ ++ if (!subscribed) { ++ rc = xenstore_subscribe_to_hotplug_status(handle, ++ "vtpm", ++ e[0], ++ token); ++ if (rc != 0) ++ break; ++ subscribed = 1; ++ } ++ rc = select(fd+1, &readfds, NULL, NULL, &tv); ++ /* get what's available -- drain the fd */ ++ f = xs_read_watch(handle, &nr); ++ ctr++; ++ free(f); ++ if (ctr > 2) ++ end = 1; ++ } ++ } while (end == 0); ++ free(e); ++ } ++ if (subscribed) { ++ /* clean up */ ++ xenstore_unsubscribe_from_hotplug_status(handle, ++ "vtpm", ++ e[0], ++ token); ++ } ++ xs_daemon_close(handle); ++ } ++ if (number == VTPM_BAD_INSTANCE) ++ fprintf(logfile, "no valid vtpm instance"); ++ else ++ fprintf(logfile,"vtpm instance:%d\n",number); ++ return number; ++} +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-12-08 18:20:53.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:21:18.000000000 +0000 +@@ -932,6 +932,10 @@ + void piix4_pm_init(PCIBus *bus, int devfn); + void acpi_bios_init(void); + ++/* tpm_tis.c */ ++int has_tpm_device(void); ++void tpm_tis_init(SetIRQFunc *set_irq, void *irq_opaque, int irq); ++ + /* piix4acpi.c */ + extern void pci_piix4_acpi_init(PCIBus *bus, int devfn); + diff --git a/tools/ioemu/patches/usb-uhci-buffer-size b/tools/ioemu/patches/usb-uhci-buffer-size new file mode 100644 index 0000000000..785692ff47 --- /dev/null +++ b/tools/ioemu/patches/usb-uhci-buffer-size @@ -0,0 +1,25 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID f19ddc0ee3e68d5d8a250ba0a20ab7d90ae9a36a +# Parent f66f7c3a82a7420d80714b0d349ee9a24b50ec28 +[QEMU] usb-uhci: Data buffer is too small + +The data buffer is only 1280 bytes long but the user-supplied length +can be as large as 0x7ff. This patch extends the buffer to 2048 +bytes. + +Signed-off-by: Herbert Xu + +Index: ioemu/hw/usb-uhci.c +=================================================================== +--- ioemu.orig/hw/usb-uhci.c 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/hw/usb-uhci.c 2006-12-08 18:23:06.000000000 +0000 +@@ -421,7 +421,7 @@ + static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask) + { + uint8_t pid; +- uint8_t buf[1280]; ++ uint8_t buf[2048]; + int len, max_len, err, ret; + + if (td->ctrl & TD_CTRL_IOC) { diff --git a/tools/ioemu/patches/vnc-access-monitor-vt b/tools/ioemu/patches/vnc-access-monitor-vt index 0320a978ca..4607815ea8 100644 --- a/tools/ioemu/patches/vnc-access-monitor-vt +++ b/tools/ioemu/patches/vnc-access-monitor-vt @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:33:46.000000000 +0100 +--- ioemu.orig/vnc.c 2006-12-06 23:46:11.000000000 +0000 ++++ ioemu/vnc.c 2006-12-06 23:46:11.000000000 +0000 @@ -33,6 +33,10 @@ #include "vnc_keysym.h" #include "keymaps.c" @@ -22,7 +22,7 @@ Index: ioemu/vnc.c }; #define DIRTY_PIXEL_BITS 64 -@@ -794,16 +800,80 @@ +@@ -796,16 +802,80 @@ static void do_key_event(VncState *vs, int down, uint32_t sym) { diff --git a/tools/ioemu/patches/vnc-backoff-screen-scan b/tools/ioemu/patches/vnc-backoff-screen-scan index 813a63ae48..172a265bc8 100644 --- a/tools/ioemu/patches/vnc-backoff-screen-scan +++ b/tools/ioemu/patches/vnc-backoff-screen-scan @@ -1,7 +1,7 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:33:17.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:33:24.000000000 +0100 +--- ioemu.orig/vnc.c 2006-12-06 23:46:12.000000000 +0000 ++++ ioemu/vnc.c 2006-12-06 23:46:12.000000000 +0000 @@ -28,7 +28,19 @@ #include "qemu_socket.h" #include @@ -45,7 +45,7 @@ Index: ioemu/vnc.c int ctl_keys; /* Ctrl+Alt starts calibration */ }; -@@ -381,7 +392,7 @@ +@@ -383,7 +394,7 @@ int y = 0; int pitch = ds->linesize; VncState *vs = ds->opaque; @@ -54,7 +54,7 @@ Index: ioemu/vnc.c if (src_x < vs->visible_x || src_y < vs->visible_y || dst_x < vs->visible_x || dst_y < vs->visible_y || -@@ -391,10 +402,8 @@ +@@ -393,10 +404,8 @@ (dst_y + h) > (vs->visible_y + vs->visible_h)) updating_client = 0; @@ -66,7 +66,7 @@ Index: ioemu/vnc.c if (dst_y > src_y) { y = h - 1; -@@ -446,110 +455,149 @@ +@@ -448,110 +457,149 @@ static void _vnc_update_client(void *opaque) { VncState *vs = opaque; @@ -299,7 +299,7 @@ Index: ioemu/vnc.c } static void vnc_update_client(void *opaque) -@@ -562,8 +610,10 @@ +@@ -564,8 +612,10 @@ static void vnc_timer_init(VncState *vs) { @@ -311,7 +311,7 @@ Index: ioemu/vnc.c } static void vnc_dpy_refresh(DisplayState *ds) -@@ -623,7 +673,6 @@ +@@ -625,7 +675,6 @@ vs->csock = -1; buffer_reset(&vs->input); buffer_reset(&vs->output); @@ -319,7 +319,7 @@ Index: ioemu/vnc.c return 0; } return ret; -@@ -895,7 +944,6 @@ +@@ -897,7 +946,6 @@ int x_position, int y_position, int w, int h) { @@ -327,7 +327,7 @@ Index: ioemu/vnc.c if (!incremental) framebuffer_set_updated(vs, x_position, y_position, w, h); vs->visible_x = x_position; -@@ -1018,6 +1066,7 @@ +@@ -1020,6 +1068,7 @@ { int i; uint16_t limit; @@ -335,7 +335,7 @@ Index: ioemu/vnc.c switch (data[0]) { case 0: -@@ -1061,12 +1110,18 @@ +@@ -1063,12 +1112,18 @@ if (len == 1) return 8; @@ -356,8 +356,8 @@ Index: ioemu/vnc.c case 6: Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:17.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:24.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-06 23:46:12.000000000 +0000 ++++ ioemu/vl.c 2006-12-06 23:46:12.000000000 +0000 @@ -726,6 +726,12 @@ } } @@ -373,8 +373,8 @@ Index: ioemu/vl.c void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:33:17.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:33:24.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-06 23:46:12.000000000 +0000 ++++ ioemu/vl.h 2006-12-06 23:46:12.000000000 +0000 @@ -407,6 +407,7 @@ void qemu_free_timer(QEMUTimer *ts); void qemu_del_timer(QEMUTimer *ts); diff --git a/tools/ioemu/patches/vnc-display-find-unused b/tools/ioemu/patches/vnc-display-find-unused index bb4f36a9da..2f7e509153 100644 --- a/tools/ioemu/patches/vnc-display-find-unused +++ b/tools/ioemu/patches/vnc-display-find-unused @@ -1,8 +1,8 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:31:09.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:31:36.000000000 +0100 -@@ -1195,7 +1195,7 @@ +--- ioemu.orig/vnc.c 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 02:02:37.000000000 +0000 +@@ -1197,7 +1197,7 @@ } } @@ -11,7 +11,7 @@ Index: ioemu/vnc.c { struct sockaddr_in addr; int reuse_addr, ret; -@@ -1226,10 +1226,6 @@ +@@ -1228,10 +1228,6 @@ exit(1); } @@ -22,7 +22,7 @@ Index: ioemu/vnc.c reuse_addr = 1; ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse_addr, sizeof(reuse_addr)); -@@ -1238,7 +1234,16 @@ +@@ -1240,7 +1236,16 @@ exit(1); } @@ -39,7 +39,7 @@ Index: ioemu/vnc.c fprintf(stderr, "bind() failed\n"); exit(1); } -@@ -1259,6 +1264,8 @@ +@@ -1261,6 +1266,8 @@ vs->ds->dpy_refresh = vnc_dpy_refresh; vnc_dpy_resize(vs->ds, 640, 400); @@ -50,8 +50,8 @@ Index: ioemu/vnc.c int vnc_start_viewer(int port) Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:31:09.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:31:41.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:37.000000000 +0000 @@ -121,6 +121,7 @@ static DisplayState display_state; int nographic; @@ -84,7 +84,7 @@ Index: ioemu/vl.c /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, -@@ -5873,6 +5877,7 @@ +@@ -5857,6 +5861,7 @@ snapshot = 0; nographic = 0; vncviewer = 0; @@ -92,7 +92,7 @@ Index: ioemu/vl.c kernel_filename = NULL; kernel_cmdline = ""; #ifdef TARGET_PPC -@@ -6270,6 +6275,11 @@ +@@ -6254,6 +6259,11 @@ case QEMU_OPTION_vncviewer: vncviewer++; break; @@ -104,7 +104,7 @@ Index: ioemu/vl.c } } } -@@ -6483,7 +6493,7 @@ +@@ -6468,7 +6478,7 @@ if (nographic) { dumb_display_init(ds); } else if (vnc_display != -1) { @@ -115,8 +115,8 @@ Index: ioemu/vl.c } else { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:31:09.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:31:36.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:37.000000000 +0000 @@ -785,7 +785,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen); diff --git a/tools/ioemu/patches/vnc-fixes b/tools/ioemu/patches/vnc-fixes index 7e08920961..0c847affa0 100644 --- a/tools/ioemu/patches/vnc-fixes +++ b/tools/ioemu/patches/vnc-fixes @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:19:36.000000000 +0100 -@@ -6534,8 +6534,10 @@ +--- ioemu.orig/vl.c 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:36.000000000 +0000 +@@ -6519,8 +6519,10 @@ } } @@ -17,8 +17,8 @@ Index: ioemu/vl.c if (use_gdbstub) { Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:20:00.000000000 +0100 +--- ioemu.orig/vnc.c 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 02:02:36.000000000 +0000 @@ -3,6 +3,7 @@ * * Copyright (C) 2006 Anthony Liguori @@ -92,7 +92,7 @@ Index: ioemu/vnc.c static inline void vnc_set_bit(uint32_t *d, int k) { d[k >> 5] |= 1 << (k & 0x1f); -@@ -139,20 +161,35 @@ +@@ -139,20 +161,37 @@ } return 0; } @@ -121,6 +121,8 @@ Index: ioemu/vnc.c mask = ~(0ULL); + h += y; ++ if (h > vs->ds->height) ++ h = vs->ds->height; for (; y < h; y++) - vs->dirty_row[y] |= mask; + row[y] |= mask; @@ -134,7 +136,7 @@ Index: ioemu/vnc.c } static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, -@@ -169,16 +206,23 @@ +@@ -169,16 +208,23 @@ static void vnc_dpy_resize(DisplayState *ds, int w, int h) { VncState *vs = ds->opaque; @@ -160,7 +162,7 @@ Index: ioemu/vnc.c ds->width = w; ds->height = h; ds->linesize = w * vs->depth; -@@ -191,6 +235,10 @@ +@@ -191,6 +237,10 @@ vs->width = ds->width; vs->height = ds->height; } @@ -171,7 +173,7 @@ Index: ioemu/vnc.c } /* fastest code */ -@@ -326,8 +374,20 @@ +@@ -326,8 +376,20 @@ int y = 0; int pitch = ds->linesize; VncState *vs = ds->opaque; @@ -193,7 +195,7 @@ Index: ioemu/vnc.c if (dst_y > src_y) { y = h - 1; -@@ -349,31 +409,34 @@ +@@ -349,31 +411,34 @@ old_row += pitch; } @@ -240,7 +242,7 @@ Index: ioemu/vnc.c { VncState *vs = opaque; int64_t now = qemu_get_clock(rt_clock); -@@ -382,14 +445,18 @@ +@@ -382,14 +447,18 @@ int y; char *row; char *old_row; @@ -262,7 +264,7 @@ Index: ioemu/vnc.c /* Walk through the dirty map and eliminate tiles that really aren't dirty */ -@@ -397,23 +464,25 @@ +@@ -397,23 +466,25 @@ old_row = vs->old_data; for (y = 0; y < vs->ds->height; y++) { @@ -297,7 +299,7 @@ Index: ioemu/vnc.c } } -@@ -421,7 +490,8 @@ +@@ -421,7 +492,8 @@ old_row += vs->ds->linesize; } @@ -307,7 +309,7 @@ Index: ioemu/vnc.c return; /* Count rectangles */ -@@ -431,34 +501,56 @@ +@@ -431,34 +503,56 @@ saved_offset = vs->output.offset; vnc_write_u16(vs, 0); @@ -375,7 +377,7 @@ Index: ioemu/vnc.c } static void vnc_timer_init(VncState *vs) -@@ -469,8 +561,6 @@ +@@ -469,8 +563,6 @@ static void vnc_dpy_refresh(DisplayState *ds) { @@ -384,7 +386,7 @@ Index: ioemu/vnc.c vga_hw_update(); } -@@ -506,7 +596,7 @@ +@@ -506,7 +598,7 @@ static void buffer_reset(Buffer *buffer) { @@ -393,7 +395,7 @@ Index: ioemu/vnc.c } static void buffer_append(Buffer *buffer, const void *data, size_t len) -@@ -547,12 +637,12 @@ +@@ -547,12 +639,12 @@ if (!ret) return; @@ -409,7 +411,7 @@ Index: ioemu/vnc.c } static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) -@@ -584,11 +674,11 @@ +@@ -584,11 +676,11 @@ return; if (!ret) { @@ -424,7 +426,7 @@ Index: ioemu/vnc.c } } -@@ -596,9 +686,9 @@ +@@ -596,9 +688,9 @@ { buffer_reserve(&vs->output, len); @@ -437,7 +439,7 @@ Index: ioemu/vnc.c buffer_append(&vs->output, data, len); } -@@ -720,22 +810,25 @@ +@@ -720,22 +812,25 @@ do_key_event(vs, down, sym); } @@ -474,7 +476,7 @@ Index: ioemu/vnc.c qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock)); } -@@ -843,8 +936,6 @@ +@@ -843,8 +938,6 @@ } vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); @@ -483,7 +485,7 @@ Index: ioemu/vnc.c vga_hw_invalidate(); vga_hw_update(); -@@ -924,6 +1015,8 @@ +@@ -924,6 +1017,8 @@ { char pad[3] = { 0, 0, 0 }; @@ -492,7 +494,7 @@ Index: ioemu/vnc.c vs->width = vs->ds->width; vs->height = vs->ds->height; vnc_write_u16(vs, vs->ds->width); -@@ -1010,11 +1103,11 @@ +@@ -1010,11 +1105,11 @@ vnc_write(vs, "RFB 003.003\n", 12); vnc_flush(vs); vnc_read_when(vs, protocol_version, 12); @@ -506,7 +508,7 @@ Index: ioemu/vnc.c } } -@@ -1071,17 +1164,15 @@ +@@ -1071,17 +1166,15 @@ exit(1); } @@ -529,8 +531,8 @@ Index: ioemu/vnc.c } Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 13:47:23.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:19:36.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:36.000000000 +0000 @@ -319,6 +319,7 @@ int is_graphic_console(void); CharDriverState *text_console_init(DisplayState *ds); diff --git a/tools/ioemu/patches/vnc-japan-keymap b/tools/ioemu/patches/vnc-japan-keymap new file mode 100644 index 0000000000..86135a9b22 --- /dev/null +++ b/tools/ioemu/patches/vnc-japan-keymap @@ -0,0 +1,39 @@ +# HG changeset patch +# User kasai.takanori@jp.fujitsu.com +# Node ID ea1ffa51b4121d36cffdc90276378a6ed334c2cc +# Parent edd592c823a520d4072a95ac39beb2012c05321e +Add the Japanese keymap for VNC Server. + +Signed-off-by: Takanori Kasai < kasai.takanori@jp.fujitsu.com > + +Index: ioemu/keymaps/ja +=================================================================== +--- ioemu.orig/keymaps/ja 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/keymaps/ja 2006-12-08 18:21:56.000000000 +0000 +@@ -102,3 +102,6 @@ + Henkan_Mode 0x79 + Katakana 0x70 + Muhenkan 0x7b ++Henkan_Mode_Real 0x79 ++Henkan_Mode_Ultra 0x79 ++backslash_ja 0x73 +Index: ioemu/vnc_keysym.h +=================================================================== +--- ioemu.orig/vnc_keysym.h 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/vnc_keysym.h 2006-12-08 18:21:56.000000000 +0000 +@@ -271,5 +271,15 @@ + {"Num_Lock", 0xff7f}, /* XK_Num_Lock */ + {"Pause", 0xff13}, /* XK_Pause */ + {"Escape", 0xff1b}, /* XK_Escape */ ++ ++ /* localized keys */ ++{"BackApostrophe", 0xff21}, ++{"Muhenkan", 0xff22}, ++{"Katakana", 0xff25}, ++{"Zenkaku_Hankaku", 0xff29}, ++{"Henkan_Mode_Real", 0xff23}, ++{"Henkan_Mode_Ultra", 0xff3e}, ++{"backslash_ja", 0xffa5}, ++ + {0,0}, + }; diff --git a/tools/ioemu/patches/vnc-listen-specific-interface b/tools/ioemu/patches/vnc-listen-specific-interface index 3c42abb94c..a11a554a52 100644 --- a/tools/ioemu/patches/vnc-listen-specific-interface +++ b/tools/ioemu/patches/vnc-listen-specific-interface @@ -20,8 +20,8 @@ Signed-off-by: Daniel P. Berrange Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:34:28.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:37.000000000 +0000 @@ -122,6 +122,7 @@ int nographic; int vncviewer; @@ -95,7 +95,7 @@ Index: ioemu/vl.c /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, -@@ -5905,6 +5915,8 @@ +@@ -5889,6 +5899,8 @@ nb_nics = 0; /* default mac address of the first network interface */ @@ -103,8 +103,8 @@ Index: ioemu/vl.c + memset(&vnclisten_addr.sin_addr, 0, sizeof(vnclisten_addr.sin_addr)); /* init debug */ - sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%d.log", getpid()); -@@ -6280,6 +6292,9 @@ + sprintf(qemu_dm_logfilename, "/var/log/xen/qemu-dm.%ld.log", (long)getpid()); +@@ -6264,6 +6276,9 @@ if (vnc_display == -1) vnc_display = 0; break; @@ -114,7 +114,7 @@ Index: ioemu/vl.c } } } -@@ -6493,7 +6508,7 @@ +@@ -6478,7 +6493,7 @@ if (nographic) { dumb_display_init(ds); } else if (vnc_display != -1) { @@ -125,8 +125,8 @@ Index: ioemu/vl.c } else { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:34:22.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:37.000000000 +0000 @@ -37,6 +37,8 @@ #include #include @@ -147,9 +147,9 @@ Index: ioemu/vl.h /* ide.c */ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:34:22.000000000 +0100 -@@ -1195,9 +1195,8 @@ +--- ioemu.orig/vnc.c 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 02:02:37.000000000 +0000 +@@ -1197,9 +1197,8 @@ } } @@ -160,7 +160,7 @@ Index: ioemu/vnc.c int reuse_addr, ret; VncState *vs; -@@ -1235,11 +1234,10 @@ +@@ -1237,11 +1236,10 @@ } retry: diff --git a/tools/ioemu/patches/vnc-monitor-shift-key-processing b/tools/ioemu/patches/vnc-monitor-shift-key-processing new file mode 100644 index 0000000000..afd164ad94 --- /dev/null +++ b/tools/ioemu/patches/vnc-monitor-shift-key-processing @@ -0,0 +1,60 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID 582d21e2d3cd12a13ad4debee9af8bb0f1be413a +# Parent b7095209e31ae1f52cd4b196225a360543e37a80 +[QEMU] Do shift-key processing in QEMU monitor terminal when connected via VNC. +Signed-off-by: Daniel P. Berrange + +Index: ioemu/vnc.c +=================================================================== +--- ioemu.orig/vnc.c 2006-12-08 18:21:36.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 18:23:12.000000000 +0000 +@@ -114,6 +114,7 @@ + int visible_h; + + int ctl_keys; /* Ctrl+Alt starts calibration */ ++ int shift_keys; /* Shift / CapsLock keys */ + }; + + #define DIRTY_PIXEL_BITS 64 +@@ -870,9 +871,12 @@ + } else if (down) { + int qemu_keysym = 0; + +- if (sym <= 128) /* normal ascii */ ++ if (sym <= 128) { /* normal ascii */ ++ int shifted = vs->shift_keys == 1 || vs->shift_keys == 2; + qemu_keysym = sym; +- else { ++ if (sym >= 'a' && sym <= 'z' && shifted) ++ qemu_keysym -= 'a' - 'A'; ++ } else { + switch (sym) { + case XK_Up: qemu_keysym = QEMU_KEY_UP; break; + case XK_Down: qemu_keysym = QEMU_KEY_DOWN; break; +@@ -903,6 +907,10 @@ + vs->ctl_keys |= 2; + break; + ++ case XK_Shift_L: ++ vs->shift_keys |= 1; ++ break; ++ + default: + break; + } +@@ -916,6 +924,14 @@ + vs->ctl_keys &= ~2; + break; + ++ case XK_Shift_L: ++ vs->shift_keys &= ~1; ++ break; ++ ++ case XK_Caps_Lock: ++ vs->shift_keys ^= 2; ++ break; ++ + case XK_1 ... XK_9: + if ((vs->ctl_keys & 3) != 3) + break; diff --git a/tools/ioemu/patches/vnc-numpad-handling b/tools/ioemu/patches/vnc-numpad-handling new file mode 100644 index 0000000000..d55de2da20 --- /dev/null +++ b/tools/ioemu/patches/vnc-numpad-handling @@ -0,0 +1,236 @@ +# HG changeset patch +# User Ewan Mellor +# Node ID c7f4a89eb054a1ad411da1e4cdc8aeda1a98c4fa +# Parent 565cd8f32c70da8ae7dbaaeb9dff28aa8b6307e1 +Fix numpad handling in QEMU's VNC server. The keymaps that we have include +information on which keys change depending upon the numlock setting, but +this isn't being used. By forcing numlock on and off as necessary, when +receiving these keysyms through the VNC connection, we ensure that the +server's numlock status is the same as the client's. + +Signed-off-by: Ewan Mellor + +Index: ioemu/keymaps.c +=================================================================== +--- ioemu.orig/keymaps.c 2006-12-06 23:41:30.000000000 +0000 ++++ ioemu/keymaps.c 2006-12-08 18:20:27.000000000 +0000 +@@ -36,8 +36,10 @@ + #define MAX_EXTRA_COUNT 256 + typedef struct { + uint16_t keysym2keycode[MAX_NORMAL_KEYCODE]; ++ int keysym2numlock[MAX_NORMAL_KEYCODE]; + struct { + int keysym; ++ int numlock; + uint16_t keycode; + } keysym2keycode_extra[MAX_EXTRA_COUNT]; + int extra_count; +@@ -50,6 +52,8 @@ + char file_name[1024]; + char line[1024]; + int len; ++ int *keycode2numlock; ++ int i; + + snprintf(file_name, sizeof(file_name), + "%s/keymaps/%s", bios_dir, language); +@@ -63,6 +67,15 @@ + "Could not read keymap file: '%s'\n", file_name); + return 0; + } ++ ++ /* Allocate a temporary map tracking which keycodes change when numlock is ++ set. Keycodes are 16 bit, so 65536 is safe. */ ++ keycode2numlock = malloc(65536 * sizeof(int)); ++ if (!keycode2numlock) { ++ perror("Could not read keymap file"); ++ return 0; ++ } ++ + for(;;) { + if (fgets(line, 1024, f) == NULL) + break; +@@ -86,13 +99,19 @@ + if (keysym == 0) { + // fprintf(stderr, "Warning: unknown keysym %s\n", line); + } else { +- const char *rest = end_of_keysym + 1; +- int keycode = strtol(rest, NULL, 0); ++ char *rest = end_of_keysym + 1; ++ int keycode = strtol(rest, &rest, 0); ++ int numlock = (rest != NULL && ++ strstr(rest, "numlock") != NULL); ++ ++ keycode2numlock[keycode] = numlock; ++ + /* if(keycode&0x80) + keycode=(keycode<<8)^0x80e0; */ + if (keysym < MAX_NORMAL_KEYCODE) { + //fprintf(stderr,"Setting keysym %s (%d) to %d\n",line,keysym,keycode); + k->keysym2keycode[keysym] = keycode; ++ k->keysym2numlock[keysym] = numlock; + } else { + if (k->extra_count >= MAX_EXTRA_COUNT) { + fprintf(stderr, +@@ -107,6 +126,8 @@ + keysym = keysym; + k->keysym2keycode_extra[k->extra_count]. + keycode = keycode; ++ k->keysym2keycode_extra[k->extra_count]. ++ numlock = numlock; + k->extra_count++; + } + } +@@ -115,6 +136,22 @@ + } + } + fclose(f); ++ ++ for (i = 0; i < MAX_NORMAL_KEYCODE; i++) { ++ if (k->keysym2numlock[i] != 1) { ++ k->keysym2numlock[i] = -keycode2numlock[k->keysym2keycode[i]]; ++ } ++ } ++ ++ for (i = 0; i < k->extra_count; i++) { ++ if (k->keysym2keycode_extra[i].numlock != 1) { ++ k->keysym2keycode_extra[i].numlock = ++ -keycode2numlock[k->keysym2keycode_extra[i].keycode]; ++ } ++ } ++ ++ free(keycode2numlock); ++ + return k; + } + +@@ -143,3 +180,25 @@ + } + return 0; + } ++ ++/** ++ * Returns 1 if the given keysym requires numlock to be pressed, -1 if it ++ * requires it to be cleared, and 0 otherwise. ++ */ ++static int keysym2numlock(void *kbd_layout, int keysym) ++{ ++ kbd_layout_t *k = kbd_layout; ++ if (keysym < MAX_NORMAL_KEYCODE) { ++ return k->keysym2numlock[keysym]; ++ } else { ++ int i; ++#ifdef XK_ISO_Left_Tab ++ if (keysym == XK_ISO_Left_Tab) ++ keysym = XK_Tab; ++#endif ++ for (i = 0; i < k->extra_count; i++) ++ if (k->keysym2keycode_extra[i].keysym == keysym) ++ return k->keysym2keycode_extra[i].numlock; ++ } ++ return 0; ++} +Index: ioemu/vnc.c +=================================================================== +--- ioemu.orig/vnc.c 2006-12-08 18:18:26.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 18:19:43.000000000 +0000 +@@ -115,6 +115,7 @@ + + int ctl_keys; /* Ctrl+Alt starts calibration */ + int shift_keys; /* Shift / CapsLock keys */ ++ int numlock; + }; + + #define DIRTY_PIXEL_BITS 64 +@@ -854,14 +855,40 @@ + } + } + ++static void press_key(VncState *vs, int keycode) ++{ ++ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) & 0x7f); ++ kbd_put_keycode(keysym2scancode(vs->kbd_layout, keycode) | 0x80); ++} ++ + static void do_key_event(VncState *vs, int down, uint32_t sym) + { + sym &= 0xFFFF; + + if (is_graphic_console()) { + int keycode; ++ int numlock; + + keycode = keysym2scancode(vs->kbd_layout, sym); ++ numlock = keysym2numlock(vs->kbd_layout, sym); ++ ++ /* If the numlock state needs to change then simulate an additional ++ keypress before sending this one. This will happen if the user ++ toggles numlock away from the VNC window. ++ */ ++ if (numlock == 1) { ++ if (!vs->numlock) { ++ vs->numlock = 1; ++ press_key(vs, XK_Num_Lock); ++ } ++ } ++ else if (numlock == -1) { ++ if (vs->numlock) { ++ vs->numlock = 0; ++ press_key(vs, XK_Num_Lock); ++ } ++ } ++ + if (keycode & 0x80) + kbd_put_keycode(0xe0); + if (down) +@@ -932,6 +959,10 @@ + vs->shift_keys ^= 2; + break; + ++ case XK_Num_Lock: ++ vs->numlock = !vs->numlock; ++ break; ++ + case XK_1 ... XK_9: + if ((vs->ctl_keys & 3) != 3) + break; +@@ -1355,6 +1386,7 @@ + vs->lsock = -1; + vs->csock = -1; + vs->depth = 4; ++ vs->numlock = 0; + + vs->ds = ds; + +Index: ioemu/vnc_keysym.h +=================================================================== +--- ioemu.orig/vnc_keysym.h 2006-12-08 18:17:01.000000000 +0000 ++++ ioemu/vnc_keysym.h 2006-12-08 18:19:43.000000000 +0000 +@@ -231,6 +231,19 @@ + {"Home", 0xff50}, /* XK_Home */ + {"End", 0xff57}, /* XK_End */ + {"Scroll_Lock", 0xff14}, /* XK_Scroll_Lock */ ++{"KP_Home", 0xff95}, ++{"KP_Left", 0xff96}, ++{"KP_Up", 0xff97}, ++{"KP_Right", 0xff98}, ++{"KP_Down", 0xff99}, ++{"KP_Prior", 0xff9a}, ++{"KP_Page_Up", 0xff9a}, ++{"KP_Next", 0xff9b}, ++{"KP_Page_Down", 0xff9b}, ++{"KP_End", 0xff9c}, ++{"KP_Begin", 0xff9d}, ++{"KP_Insert", 0xff9e}, ++{"KP_Delete", 0xff9f}, + {"F1", 0xffbe}, /* XK_F1 */ + {"F2", 0xffbf}, /* XK_F2 */ + {"F3", 0xffc0}, /* XK_F3 */ +@@ -258,6 +271,7 @@ + {"KP_8", 0xffb8}, /* XK_KP_8 */ + {"KP_9", 0xffb9}, /* XK_KP_9 */ + {"KP_Add", 0xffab}, /* XK_KP_Add */ ++{"KP_Separator", 0xffac},/* XK_KP_Separator */ + {"KP_Decimal", 0xffae}, /* XK_KP_Decimal */ + {"KP_Divide", 0xffaf}, /* XK_KP_Divide */ + {"KP_Enter", 0xff8d}, /* XK_KP_Enter */ diff --git a/tools/ioemu/patches/vnc-password b/tools/ioemu/patches/vnc-password index 49c5d73b47..1a923ddfc0 100644 --- a/tools/ioemu/patches/vnc-password +++ b/tools/ioemu/patches/vnc-password @@ -15,9 +15,11 @@ The difference is follows. Signed-off-by: Masami Watanabe ---- ioemu/Makefile.target Fri Oct 20 09:32:16 2006 +0100 -+++ ioemu/Makefile.target Fri Oct 20 09:50:09 2006 +0100 -@@ -406,6 +406,7 @@ VL_OBJS+=sdl.o +Index: ioemu/Makefile.target +=================================================================== +--- ioemu.orig/Makefile.target 2006-12-08 18:20:53.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 18:20:53.000000000 +0000 +@@ -407,6 +407,7 @@ VL_OBJS+=sdl.o endif VL_OBJS+=vnc.o @@ -25,29 +27,31 @@ Signed-off-by: Masami Watanabe ifdef CONFIG_COCOA VL_OBJS+=cocoa.o COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit -@@ -464,6 +465,9 @@ sdl.o: sdl.c keymaps.c sdl_keysym.h - $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< - +@@ -467,6 +468,9 @@ vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h -+ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< -+ -+d3des.o: d3des.c d3des.h $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< ++d3des.o: d3des.c d3des.h ++ $(CC) $(CFLAGS) $(DEFINES) -c -o $@ $< ++ sdlaudio.o: sdlaudio.c ---- ioemu/vl.c Fri Oct 20 09:32:16 2006 +0100 -+++ ioemu/vl.c Fri Oct 20 09:50:09 2006 +0100 -@@ -170,6 +170,9 @@ time_t timeoffset = 0; + $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $< +Index: ioemu/vl.c +=================================================================== +--- ioemu.orig/vl.c 2006-12-08 18:20:52.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 18:20:53.000000000 +0000 +@@ -171,6 +171,9 @@ char domain_name[1024] = { 'H','V', 'M', 'X', 'E', 'N', '-'}; extern int domid; -+ + +char vncpasswd[64]; +unsigned char challenge[AUTHCHALLENGESIZE]; - ++ /***********************************************************/ /* x86 ISA bus support */ -@@ -5911,6 +5914,7 @@ int main(int argc, char **argv) + +@@ -5895,6 +5898,7 @@ vncunused = 0; kernel_filename = NULL; kernel_cmdline = ""; @@ -55,7 +59,7 @@ Signed-off-by: Masami Watanabe #ifndef CONFIG_DM #ifdef TARGET_PPC cdrom_index = 1; -@@ -6559,6 +6563,10 @@ int main(int argc, char **argv) +@@ -6543,6 +6547,10 @@ init_ioports(); @@ -66,9 +70,11 @@ Signed-off-by: Masami Watanabe /* terminal init */ if (nographic) { dumb_display_init(ds); ---- ioemu/vl.h Fri Oct 20 09:32:16 2006 +0100 -+++ ioemu/vl.h Fri Oct 20 09:50:09 2006 +0100 -@@ -1211,6 +1211,7 @@ void xenstore_process_event(void *opaque +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-12-08 18:20:52.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:20:53.000000000 +0000 +@@ -1214,6 +1214,7 @@ void xenstore_process_event(void *opaque); void xenstore_check_new_media_present(int timeout); void xenstore_write_vncport(int vnc_display); @@ -76,7 +82,7 @@ Signed-off-by: Masami Watanabe /* xen_platform.c */ void pci_xen_platform_init(PCIBus *bus); -@@ -1222,4 +1223,7 @@ extern char domain_name[]; +@@ -1225,4 +1226,7 @@ void destroy_hvm_domain(void); @@ -84,8 +90,10 @@ Signed-off-by: Masami Watanabe +#define AUTHCHALLENGESIZE 16 + #endif /* VL_H */ ---- ioemu/vnc.c Fri Oct 20 09:32:16 2006 +0100 -+++ ioemu/vnc.c Fri Oct 20 09:50:09 2006 +0100 +Index: ioemu/vnc.c +=================================================================== +--- ioemu.orig/vnc.c 2006-12-08 18:20:52.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 18:20:53.000000000 +0000 @@ -44,6 +44,7 @@ #include "vnc_keysym.h" @@ -94,7 +102,7 @@ Signed-off-by: Masami Watanabe #define XK_MISCELLANY #define XK_LATIN1 -@@ -137,6 +138,9 @@ static void vnc_update_client(void *opaq +@@ -137,6 +138,9 @@ static void vnc_update_client(void *opaque); static void vnc_client_read(void *opaque); static void framebuffer_set_updated(VncState *vs, int x, int y, int w, int h); @@ -104,7 +112,7 @@ Signed-off-by: Masami Watanabe #if 0 static inline void vnc_set_bit(uint32_t *d, int k) -@@ -1208,23 +1212,92 @@ static int protocol_client_init(VncState +@@ -1210,23 +1214,92 @@ return 0; } @@ -166,9 +174,8 @@ Signed-off-by: Masami Watanabe - vnc_write_u32(vs, 1); /* None */ - vnc_flush(vs); -- + - vnc_read_when(vs, protocol_client_init, 1); -+ + support = 0; + if (maj = 3) { + if (min == 3 || min ==4) { @@ -202,7 +209,7 @@ Signed-off-by: Masami Watanabe return 0; } -@@ -1342,3 +1415,32 @@ int vnc_start_viewer(int port) +@@ -1344,3 +1417,32 @@ return pid; } } @@ -235,9 +242,11 @@ Signed-off-by: Masami Watanabe + + return; +} ---- ioemu/xenstore.c Fri Oct 20 09:32:16 2006 +0100 -+++ ioemu/xenstore.c Fri Oct 20 09:50:09 2006 +0100 -@@ -213,3 +213,54 @@ void xenstore_write_vncport(int display) +Index: ioemu/xenstore.c +=================================================================== +--- ioemu.orig/xenstore.c 2006-12-08 18:20:52.000000000 +0000 ++++ ioemu/xenstore.c 2006-12-08 18:20:53.000000000 +0000 +@@ -213,3 +213,54 @@ free(portstr); free(buf); } @@ -292,8 +301,10 @@ Signed-off-by: Masami Watanabe + + return rc; +} ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ ioemu/d3des.c Fri Oct 20 09:50:09 2006 +0100 +Index: ioemu/d3des.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/d3des.c 2006-12-08 18:20:53.000000000 +0000 @@ -0,0 +1,434 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and @@ -729,8 +740,10 @@ Signed-off-by: Masami Watanabe + * + * d3des V5.0a rwo 9208.07 18:44 Graven Imagery + **********************************************************************/ ---- /dev/null Thu Jan 01 00:00:00 1970 +0000 -+++ ioemu/d3des.h Fri Oct 20 09:50:09 2006 +0100 +Index: ioemu/d3des.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ ioemu/d3des.h 2006-12-08 18:20:53.000000000 +0000 @@ -0,0 +1,51 @@ +/* + * This is D3DES (V5.09) by Richard Outerbridge with the double and diff --git a/tools/ioemu/patches/vnc-protocol-fixes b/tools/ioemu/patches/vnc-protocol-fixes index 84e53614da..7eaa4dfc4b 100644 --- a/tools/ioemu/patches/vnc-protocol-fixes +++ b/tools/ioemu/patches/vnc-protocol-fixes @@ -9,8 +9,8 @@ Signed-off-by: Steven Smith Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:28:05.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:30:11.000000000 +0100 +--- ioemu.orig/vnc.c 2006-12-06 23:46:11.000000000 +0000 ++++ ioemu/vnc.c 2006-12-06 23:46:11.000000000 +0000 @@ -26,6 +26,7 @@ #include "vl.h" @@ -19,7 +19,7 @@ Index: ioemu/vnc.c #define VNC_REFRESH_INTERVAL (1000 / 30) -@@ -677,8 +678,10 @@ +@@ -679,8 +680,10 @@ memmove(vs->input.buffer, vs->input.buffer + len, vs->input.offset - len); vs->input.offset -= len; @@ -31,7 +31,7 @@ Index: ioemu/vnc.c } } -@@ -961,8 +964,12 @@ +@@ -963,8 +966,12 @@ if (len == 1) return 4; @@ -46,7 +46,7 @@ Index: ioemu/vnc.c limit = read_u16(data, 2); for (i = 0; i < limit; i++) { -@@ -996,8 +1003,12 @@ +@@ -998,8 +1005,12 @@ if (len == 1) return 8; diff --git a/tools/ioemu/patches/vnc-start-vncviewer b/tools/ioemu/patches/vnc-start-vncviewer index 95080b9995..e897b09c02 100644 --- a/tools/ioemu/patches/vnc-start-vncviewer +++ b/tools/ioemu/patches/vnc-start-vncviewer @@ -1,8 +1,8 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:33:46.000000000 +0100 -@@ -1187,3 +1187,25 @@ +--- ioemu.orig/vnc.c 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vnc.c 2006-12-08 02:02:36.000000000 +0000 +@@ -1189,3 +1189,25 @@ vnc_dpy_resize(vs->ds, 640, 400); } @@ -30,8 +30,8 @@ Index: ioemu/vnc.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:46.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:36.000000000 +0000 @@ -120,6 +120,7 @@ int bios_size; static DisplayState display_state; @@ -64,7 +64,7 @@ Index: ioemu/vl.c /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, -@@ -5868,6 +5872,7 @@ +@@ -5852,6 +5856,7 @@ #endif snapshot = 0; nographic = 0; @@ -72,7 +72,7 @@ Index: ioemu/vl.c kernel_filename = NULL; kernel_cmdline = ""; #ifdef TARGET_PPC -@@ -6262,6 +6267,9 @@ +@@ -6246,6 +6251,9 @@ case QEMU_OPTION_acpi: acpi_enabled = 1; break; @@ -82,7 +82,7 @@ Index: ioemu/vl.c } } } -@@ -6476,6 +6484,8 @@ +@@ -6461,6 +6469,8 @@ dumb_display_init(ds); } else if (vnc_display != -1) { vnc_display_init(ds, vnc_display); @@ -93,8 +93,8 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:33:46.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:36.000000000 +0000 @@ -786,6 +786,7 @@ /* vnc.c */ diff --git a/tools/ioemu/patches/vnc-title-domain-name b/tools/ioemu/patches/vnc-title-domain-name index 2ba1489cf9..0c837147ad 100644 --- a/tools/ioemu/patches/vnc-title-domain-name +++ b/tools/ioemu/patches/vnc-title-domain-name @@ -1,8 +1,8 @@ Index: ioemu/vnc.c =================================================================== ---- ioemu.orig/vnc.c 2006-10-24 14:33:46.000000000 +0100 -+++ ioemu/vnc.c 2006-10-24 14:33:46.000000000 +0100 -@@ -1024,6 +1024,7 @@ +--- ioemu.orig/vnc.c 2006-12-06 23:46:11.000000000 +0000 ++++ ioemu/vnc.c 2006-12-06 23:46:11.000000000 +0000 +@@ -1026,6 +1026,7 @@ static int protocol_client_init(VncState *vs, char *data, size_t len) { @@ -10,7 +10,7 @@ Index: ioemu/vnc.c char pad[3] = { 0, 0, 0 }; vga_hw_update(); -@@ -1071,8 +1072,10 @@ +@@ -1073,8 +1074,10 @@ vnc_write(vs, pad, 3); /* padding */ diff --git a/tools/ioemu/patches/xen-build b/tools/ioemu/patches/xen-build index 8aae60d005..016b37771b 100644 --- a/tools/ioemu/patches/xen-build +++ b/tools/ioemu/patches/xen-build @@ -1,7 +1,7 @@ Index: ioemu/Makefile =================================================================== ---- ioemu.orig/Makefile 2006-10-24 14:37:25.000000000 +0100 -+++ ioemu/Makefile 2006-10-24 14:37:28.000000000 +0100 +--- ioemu.orig/Makefile 2006-12-08 01:26:04.000000000 +0000 ++++ ioemu/Makefile 2006-12-08 01:26:06.000000000 +0000 @@ -1,11 +1,14 @@ # Makefile for QEMU. @@ -85,8 +85,8 @@ Index: ioemu/Makefile info: qemu-doc.info qemu-tech.info Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-10-24 14:37:25.000000000 +0100 -+++ ioemu/Makefile.target 2006-10-24 14:40:25.000000000 +0100 +--- ioemu.orig/Makefile.target 2006-12-08 01:26:04.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:05.000000000 +0000 @@ -1,5 +1,8 @@ include config.mak @@ -120,9 +120,13 @@ Index: ioemu/Makefile.target #CFLAGS+=-Werror LDFLAGS=-g LIBS= -@@ -167,6 +177,9 @@ +@@ -165,8 +175,12 @@ - DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE + ######################################################### + +-DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE ++DEFINES+=-D_GNU_SOURCE ++#-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LIBS+=-lm +LIBS+=-L../../libxc -lxenctrl -lxenguest +LIBS+=-L../../xenstore -lxenstore @@ -130,7 +134,7 @@ Index: ioemu/Makefile.target ifndef CONFIG_USER_ONLY LIBS+=-lz endif -@@ -281,7 +294,7 @@ +@@ -281,7 +295,7 @@ all: $(PROGS) $(QEMU_USER): $(OBJS) @@ -139,7 +143,7 @@ Index: ioemu/Makefile.target ifeq ($(ARCH),alpha) # Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of # the address space (31 bit so sign extending doesn't matter) -@@ -528,10 +541,16 @@ +@@ -528,10 +542,16 @@ clean: rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o @@ -159,8 +163,8 @@ Index: ioemu/Makefile.target include .depend Index: ioemu/configure =================================================================== ---- ioemu.orig/configure 2006-10-24 14:37:25.000000000 +0100 -+++ ioemu/configure 2006-10-24 14:40:20.000000000 +0100 +--- ioemu.orig/configure 2006-12-08 01:26:04.000000000 +0000 ++++ ioemu/configure 2006-12-08 01:40:58.000000000 +0000 @@ -18,8 +18,8 @@ # default parameters diff --git a/tools/ioemu/patches/xen-mm b/tools/ioemu/patches/xen-mm index 28289837f9..8587c8cdeb 100644 --- a/tools/ioemu/patches/xen-mm +++ b/tools/ioemu/patches/xen-mm @@ -1,7 +1,7 @@ Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-08-17 19:36:00.588166019 +0100 -+++ ioemu/hw/pc.c 2006-08-17 19:37:36.704485734 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 02:00:38.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 02:02:07.000000000 +0000 @@ -646,7 +646,9 @@ } @@ -25,8 +25,8 @@ Index: ioemu/hw/pc.c isa_bios_size = bios_size; Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-08-17 19:36:00.667157242 +0100 -+++ ioemu/vl.c 2006-08-17 19:47:08.538087284 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:00:39.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:28.000000000 +0000 @@ -158,6 +158,8 @@ int acpi_enabled = 1; int fd_bootchk = 1; @@ -60,7 +60,7 @@ Index: ioemu/vl.c break; case QEMU_OPTION_l: { -@@ -6133,12 +6140,67 @@ +@@ -6133,12 +6140,61 @@ /* init the memory */ phys_ram_size = ram_size + vga_ram_size + bios_size; @@ -85,14 +85,8 @@ Index: ioemu/vl.c + exit(-1); + } + -+ if (xc_get_pfn_list(xc_handle, domid, page_array, nr_pages) != nr_pages) { -+ fprintf(logfile, "xc_get_pfn_list returned error %d\n", errno); -+ exit(-1); -+ } -+ -+ if (ram_size > HVM_BELOW_4G_RAM_END) -+ for (i = 0; i < nr_pages - (HVM_BELOW_4G_RAM_END >> PAGE_SHIFT); i++) -+ page_array[tmp_nr_pages - 1 - i] = page_array[nr_pages - 1 - i]; ++ for ( i = 0; i < tmp_nr_pages; i++) ++ page_array[i] = i; + + phys_ram_base = xc_map_foreign_batch(xc_handle, domid, + PROT_READ|PROT_WRITE, page_array, @@ -130,8 +124,8 @@ Index: ioemu/vl.c if (cdrom_index >= 0) { Index: ioemu/hw/piix_pci.c =================================================================== ---- ioemu.orig/hw/piix_pci.c 2006-08-17 19:37:36.189542951 +0100 -+++ ioemu/hw/piix_pci.c 2006-08-17 19:38:05.806252180 +0100 +--- ioemu.orig/hw/piix_pci.c 2006-12-08 02:00:36.000000000 +0000 ++++ ioemu/hw/piix_pci.c 2006-12-08 02:02:06.000000000 +0000 @@ -399,7 +399,7 @@ uint8_t elcr[2]; @@ -143,8 +137,8 @@ Index: ioemu/hw/piix_pci.c elcr[0] = 0x00; Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-08-17 19:37:36.529505177 +0100 -+++ ioemu/vl.h 2006-08-17 19:47:32.680418959 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:00:39.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:07.000000000 +0000 @@ -39,6 +39,7 @@ #include #include "xenctrl.h" diff --git a/tools/ioemu/patches/xen-platform-device b/tools/ioemu/patches/xen-platform-device index d2fcda7452..f57d1fc477 100644 --- a/tools/ioemu/patches/xen-platform-device +++ b/tools/ioemu/patches/xen-platform-device @@ -3,9 +3,9 @@ will come later. Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-10-24 14:41:01.000000000 +0100 -+++ ioemu/Makefile.target 2006-10-24 14:41:01.000000000 +0100 -@@ -359,6 +359,7 @@ +--- ioemu.orig/Makefile.target 2006-12-08 01:41:14.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 01:41:15.000000000 +0000 +@@ -360,6 +360,7 @@ VL_OBJS+= usb-uhci.o VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o @@ -15,8 +15,8 @@ Index: ioemu/Makefile.target ifeq ($(TARGET_BASE_ARCH), ppc) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-10-24 14:41:00.000000000 +0100 -+++ ioemu/hw/pc.c 2006-10-24 14:41:01.000000000 +0100 +--- ioemu.orig/hw/pc.c 2006-12-08 01:41:13.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 01:41:15.000000000 +0000 @@ -823,6 +823,9 @@ } #endif /* !CONFIG_DM */ @@ -30,7 +30,7 @@ Index: ioemu/hw/pc.c Index: ioemu/hw/xen_platform.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/hw/xen_platform.c 2006-10-24 14:41:04.000000000 +0100 ++++ ioemu/hw/xen_platform.c 2006-12-08 01:41:15.000000000 +0000 @@ -0,0 +1,144 @@ +/* + * XEN platform fake pci device, formerly known as the event channel device @@ -178,8 +178,8 @@ Index: ioemu/hw/xen_platform.c +} Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:41:01.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:41:01.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 01:41:14.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 01:41:15.000000000 +0000 @@ -1212,6 +1212,9 @@ void xenstore_check_new_media_present(int timeout); void xenstore_write_vncport(int vnc_display); diff --git a/tools/ioemu/patches/xen-support-buffered-ioreqs b/tools/ioemu/patches/xen-support-buffered-ioreqs index 7865dda35b..10d2a9a84a 100644 --- a/tools/ioemu/patches/xen-support-buffered-ioreqs +++ b/tools/ioemu/patches/xen-support-buffered-ioreqs @@ -1,8 +1,8 @@ Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100 -@@ -5854,6 +5854,7 @@ +--- ioemu.orig/vl.c 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:37.000000000 +0000 +@@ -5838,6 +5838,7 @@ unsigned long nr_pages, tmp_nr_pages, shared_page_nr; xen_pfn_t *page_array; extern void *shared_page; @@ -10,11 +10,10 @@ Index: ioemu/vl.c char qemu_dm_logfilename[64]; -@@ -6440,6 +6441,18 @@ +@@ -6418,6 +6419,17 @@ fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", shared_page_nr, (uint64_t)(page_array[shared_page_nr])); -+ /* not yet add for IA64 */ + buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, + PROT_READ|PROT_WRITE, + page_array[shared_page_nr - 2]); @@ -31,8 +30,8 @@ Index: ioemu/vl.c #elif defined(__ia64__) Index: ioemu/target-i386-dm/helper2.c =================================================================== ---- ioemu.orig/target-i386-dm/helper2.c 2006-10-24 14:33:45.000000000 +0100 -+++ ioemu/target-i386-dm/helper2.c 2006-10-24 14:33:47.000000000 +0100 +--- ioemu.orig/target-i386-dm/helper2.c 2006-12-08 02:02:35.000000000 +0000 ++++ ioemu/target-i386-dm/helper2.c 2006-12-08 02:02:37.000000000 +0000 @@ -76,6 +76,10 @@ shared_iopage_t *shared_page = NULL; @@ -44,14 +43,14 @@ Index: ioemu/target-i386-dm/helper2.c /* the evtchn fd for polling */ int xce_handle = -1; -@@ -419,36 +423,68 @@ - req->u.data = tmp1; +@@ -435,39 +439,71 @@ + req->data = tmp1; } +void __handle_ioreq(CPUState *env, ioreq_t *req) +{ -+ if (!req->pdata_valid && req->dir == IOREQ_WRITE && req->size != 4) -+ req->u.data &= (1UL << (8 * req->size)) - 1; ++ if (!req->data_is_ptr && req->dir == IOREQ_WRITE && req->size != 4) ++ req->data &= (1UL << (8 * req->size)) - 1; + + switch (req->type) { + case IOREQ_TYPE_PIO: @@ -63,6 +62,9 @@ Index: ioemu/target-i386-dm/helper2.c + case IOREQ_TYPE_AND: + cpu_ioreq_and(env, req); + break; ++ case IOREQ_TYPE_ADD: ++ cpu_ioreq_add(env, req); ++ break; + case IOREQ_TYPE_OR: + cpu_ioreq_or(env, req); + break; @@ -109,9 +111,9 @@ Index: ioemu/target-i386-dm/helper2.c + handle_buffered_io(env); if (req) { -- if ((!req->pdata_valid) && (req->dir == IOREQ_WRITE)) { +- if ((!req->data_is_ptr) && (req->dir == IOREQ_WRITE)) { - if (req->size != 4) -- req->u.data &= (1UL << (8 * req->size))-1; +- req->data &= (1UL << (8 * req->size))-1; - } - - switch (req->type) { @@ -124,6 +126,9 @@ Index: ioemu/target-i386-dm/helper2.c - case IOREQ_TYPE_AND: - cpu_ioreq_and(env, req); - break; +- case IOREQ_TYPE_ADD: +- cpu_ioreq_add(env, req); +- break; - case IOREQ_TYPE_OR: - cpu_ioreq_or(env, req); - break; @@ -135,9 +140,9 @@ Index: ioemu/target-i386-dm/helper2.c - } + __handle_ioreq(env, req); - /* No state change if state = STATE_IORESP_HOOK */ - if (req->state == STATE_IOREQ_INPROCESS) { -@@ -466,6 +502,10 @@ + if (req->state != STATE_IOREQ_INPROCESS) { + fprintf(logfile, "Badness in I/O request ... not in service?!: " +@@ -492,6 +528,10 @@ CPUState *env = cpu_single_env; int evtchn_fd = xc_evtchn_fd(xce_handle); @@ -147,4 +152,4 @@ Index: ioemu/target-i386-dm/helper2.c + qemu_set_fd_handler(evtchn_fd, cpu_handle_ioreq, NULL, env); - env->send_event = 0; + while (1) { diff --git a/tools/ioemu/patches/xenstore-block-device-config b/tools/ioemu/patches/xenstore-block-device-config index e3782d5b65..5944e3b45f 100644 --- a/tools/ioemu/patches/xenstore-block-device-config +++ b/tools/ioemu/patches/xenstore-block-device-config @@ -1,8 +1,8 @@ Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-10-24 14:31:36.000000000 +0100 -+++ ioemu/Makefile.target 2006-10-24 14:33:28.000000000 +0100 -@@ -358,6 +358,7 @@ +--- ioemu.orig/Makefile.target 2006-12-08 02:02:36.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 02:02:37.000000000 +0000 +@@ -359,6 +359,7 @@ VL_OBJS+= cirrus_vga.o mixeng.o parallel.o acpi.o piix_pci.o VL_OBJS+= usb-uhci.o VL_OBJS+= piix4acpi.o @@ -13,7 +13,7 @@ Index: ioemu/Makefile.target Index: ioemu/xenstore.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/xenstore.c 2006-10-24 14:33:28.000000000 +0100 ++++ ioemu/xenstore.c 2006-12-08 02:02:37.000000000 +0000 @@ -0,0 +1,187 @@ +/* + * This file is subject to the terms and conditions of the GNU General @@ -117,7 +117,7 @@ Index: ioemu/xenstore.c + if (strncmp(dev, "hd", 2) || strlen(dev) != 3) + continue; + hd_index = dev[2] - 'a'; -+ if (hd_index > MAX_DISKS) ++ if (hd_index >= MAX_DISKS) + continue; + /* read the type of the device */ + if (pasprintf(&buf, "%s/device/vbd/%s/device-type", path, e[i]) == -1) @@ -204,8 +204,8 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:24.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:28.000000000 +0100 +--- ioemu.orig/vl.c 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:37.000000000 +0000 @@ -5256,9 +5256,11 @@ "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" @@ -246,7 +246,7 @@ Index: ioemu/vl.c { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386 -@@ -5817,10 +5823,16 @@ +@@ -5801,10 +5807,16 @@ #ifdef CONFIG_GDBSTUB int use_gdbstub, gdbstub_port; #endif @@ -265,7 +265,7 @@ Index: ioemu/vl.c const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; -@@ -5881,8 +5893,10 @@ +@@ -5865,8 +5877,10 @@ initrd_filename = NULL; for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; @@ -276,7 +276,7 @@ Index: ioemu/vl.c ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; bios_size = BIOS_SIZE; -@@ -5896,11 +5910,13 @@ +@@ -5880,11 +5894,13 @@ vncunused = 0; kernel_filename = NULL; kernel_cmdline = ""; @@ -290,7 +290,7 @@ Index: ioemu/vl.c cyls = heads = secs = 0; translation = BIOS_ATA_TRANSLATION_AUTO; pstrcpy(monitor_device, sizeof(monitor_device), "vc"); -@@ -5935,7 +5951,11 @@ +@@ -5919,7 +5935,11 @@ break; r = argv[optind]; if (r[0] != '-') { @@ -302,7 +302,7 @@ Index: ioemu/vl.c } else { const QEMUOption *popt; -@@ -5979,6 +5999,7 @@ +@@ -5963,6 +5983,7 @@ case QEMU_OPTION_initrd: initrd_filename = optarg; break; @@ -310,7 +310,7 @@ Index: ioemu/vl.c case QEMU_OPTION_hda: case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: -@@ -5991,6 +6012,7 @@ +@@ -5975,6 +5996,7 @@ cdrom_index = -1; } break; @@ -318,7 +318,7 @@ Index: ioemu/vl.c case QEMU_OPTION_snapshot: snapshot = 1; break; -@@ -6043,11 +6065,13 @@ +@@ -6027,11 +6049,13 @@ case QEMU_OPTION_append: kernel_cmdline = optarg; break; @@ -332,7 +332,7 @@ Index: ioemu/vl.c case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && -@@ -6305,12 +6329,18 @@ +@@ -6289,12 +6313,18 @@ } } @@ -351,7 +351,7 @@ Index: ioemu/vl.c if (!linux_boot && hd_filename[0] == '\0' && (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && -@@ -6324,6 +6354,7 @@ +@@ -6308,6 +6338,7 @@ else boot_device = 'd'; } @@ -359,7 +359,7 @@ Index: ioemu/vl.c setvbuf(stdout, NULL, _IOLBF, 0); -@@ -6456,6 +6487,7 @@ +@@ -6441,6 +6472,7 @@ #endif /* !CONFIG_DM */ @@ -367,7 +367,7 @@ Index: ioemu/vl.c /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); if (cdrom_index >= 0) { -@@ -6482,6 +6514,7 @@ +@@ -6467,6 +6499,7 @@ } } } @@ -375,7 +375,7 @@ Index: ioemu/vl.c /* we always create at least one floppy disk */ fd_table[0] = bdrv_new("fda"); -@@ -6560,6 +6593,8 @@ +@@ -6545,6 +6578,8 @@ } } @@ -386,8 +386,8 @@ Index: ioemu/vl.c kernel_filename, kernel_cmdline, initrd_filename, Index: ioemu/monitor.c =================================================================== ---- ioemu.orig/monitor.c 2006-10-24 14:31:36.000000000 +0100 -+++ ioemu/monitor.c 2006-10-24 14:33:28.000000000 +0100 +--- ioemu.orig/monitor.c 2006-12-08 02:02:35.000000000 +0000 ++++ ioemu/monitor.c 2006-12-08 02:02:37.000000000 +0000 @@ -24,6 +24,7 @@ #include "vl.h" #include "disas.h" @@ -416,8 +416,8 @@ Index: ioemu/monitor.c int i; Index: ioemu/block.c =================================================================== ---- ioemu.orig/block.c 2006-10-24 14:31:36.000000000 +0100 -+++ ioemu/block.c 2006-10-24 14:33:28.000000000 +0100 +--- ioemu.orig/block.c 2006-12-08 02:02:06.000000000 +0000 ++++ ioemu/block.c 2006-12-08 02:02:37.000000000 +0000 @@ -758,6 +758,7 @@ static void raw_close(BlockDriverState *bs) { @@ -428,8 +428,8 @@ Index: ioemu/block.c Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:33:24.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:33:28.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:37.000000000 +0000 @@ -1191,6 +1191,8 @@ void term_print_help(void); void monitor_readline(const char *prompt, int is_password, @@ -455,8 +455,8 @@ Index: ioemu/vl.h extern char domain_name[]; Index: ioemu/hw/ide.c =================================================================== ---- ioemu.orig/hw/ide.c 2006-10-24 14:31:36.000000000 +0100 -+++ ioemu/hw/ide.c 2006-10-24 14:33:28.000000000 +0100 +--- ioemu.orig/hw/ide.c 2006-12-08 02:02:35.000000000 +0000 ++++ ioemu/hw/ide.c 2006-12-08 02:02:37.000000000 +0000 @@ -1158,6 +1158,7 @@ } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, diff --git a/tools/ioemu/patches/xenstore-device-info-functions b/tools/ioemu/patches/xenstore-device-info-functions new file mode 100644 index 0000000000..f0b1d46fe4 --- /dev/null +++ b/tools/ioemu/patches/xenstore-device-info-functions @@ -0,0 +1,190 @@ +# HG changeset patch +# User kaf24@localhost.localdomain +# Node ID bbcac2aea0e8196cd75a3bf6dbe57bebf8c1e5b2 +# Parent dc973fe5633386547ce5bc8fd4cf5f2bb5b55174 +[QEMU] Helper functions to interface with the xenstore and read device information from it. + + - detect what types of devices a domain has or whether a domain has a + device of a certain type + - read the content of a variable related to a device, i.e., + hotplug-status + - subscribe to changes of the hotplug status of a device for not + having to poll the status + +Signed-off-by: Stefan Berger + +Index: ioemu/xenstore.c +=================================================================== +--- ioemu.orig/xenstore.c 2006-12-08 18:20:53.000000000 +0000 ++++ ioemu/xenstore.c 2006-12-08 18:20:53.000000000 +0000 +@@ -264,3 +264,140 @@ + + return rc; + } ++ ++ ++/* ++ * get all device instances of a certain type ++ */ ++char **xenstore_domain_get_devices(struct xs_handle *handle, ++ const char *devtype, unsigned int *num) ++{ ++ char *path; ++ char *buf = NULL; ++ char **e = NULL; ++ ++ path = xs_get_domain_path(handle, domid); ++ if (path == NULL) ++ goto out; ++ ++ if (pasprintf(&buf, "%s/device/%s", path,devtype) == -1) ++ goto out; ++ ++ e = xs_directory(handle, XBT_NULL, buf, num); ++ ++ out: ++ free(path); ++ free(buf); ++ return e; ++} ++ ++/* ++ * Check whether a domain has devices of the given type ++ */ ++int xenstore_domain_has_devtype(struct xs_handle *handle, const char *devtype) ++{ ++ int rc = 0; ++ unsigned int num; ++ char **e = xenstore_domain_get_devices(handle, devtype, &num); ++ if (e) ++ rc = 1; ++ free(e); ++ return rc; ++} ++ ++/* ++ * Function that creates a path to a variable of an instance of a ++ * certain device ++ */ ++static char *get_device_variable_path(const char *devtype, const char *inst, ++ const char *var) ++{ ++ char *buf = NULL; ++ if (pasprintf(&buf, "/local/domain/0/backend/%s/%d/%s/%s", ++ devtype, ++ domid, ++ inst, ++ var) == -1) { ++ free(buf); ++ buf = NULL; ++ } ++ return buf; ++} ++ ++char *xenstore_backend_read_variable(struct xs_handle *handle, ++ const char *devtype, const char *inst, ++ const char *var) ++{ ++ char *value = NULL; ++ char *buf = NULL; ++ unsigned int len; ++ ++ buf = get_device_variable_path(devtype, inst, var); ++ if (NULL == buf) ++ goto out; ++ ++ value = xs_read(handle, XBT_NULL, buf, &len); ++ ++ free(buf); ++ ++out: ++ return value; ++} ++ ++/* ++ Read the hotplug status variable from the backend given the type ++ of device and its instance. ++*/ ++char *xenstore_read_hotplug_status(struct xs_handle *handle, ++ const char *devtype, const char *inst) ++{ ++ return xenstore_backend_read_variable(handle, devtype, inst, ++ "hotplug-status"); ++} ++ ++/* ++ Subscribe to the hotplug status of a device given the type of device and ++ its instance. ++ In case an error occurrs, a negative number is returned. ++ */ ++int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle, ++ const char *devtype, ++ const char *inst, ++ const char *token) ++{ ++ int rc = 0; ++ char *path = get_device_variable_path(devtype, inst, "hotplug-status"); ++ ++ if (path == NULL) ++ return -1; ++ ++ if (0 == xs_watch(handle, path, token)) ++ rc = -2; ++ ++ free(path); ++ ++ return rc; ++} ++ ++/* ++ * Unsubscribe from a subscription to the status of a hotplug variable of ++ * a device. ++ */ ++int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, ++ const char *devtype, ++ const char *inst, ++ const char *token) ++{ ++ int rc = 0; ++ char *path; ++ path = get_device_variable_path(devtype, inst, "hotplug-status"); ++ if (path == NULL) ++ return -1; ++ ++ if (0 == xs_unwatch(handle, path, token)) ++ rc = -2; ++ ++ free(path); ++ ++ return rc; ++} +Index: ioemu/vl.h +=================================================================== +--- ioemu.orig/vl.h 2006-12-08 18:20:53.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:20:53.000000000 +0000 +@@ -1216,6 +1216,25 @@ + void xenstore_write_vncport(int vnc_display); + int xenstore_read_vncpasswd(int domid); + ++int xenstore_domain_has_devtype(struct xs_handle *handle, ++ const char *devtype); ++char **xenstore_domain_get_devices(struct xs_handle *handle, ++ const char *devtype, unsigned int *num); ++char *xenstore_read_hotplug_status(struct xs_handle *handle, ++ const char *devtype, const char *inst); ++char *xenstore_backend_read_variable(struct xs_handle *, ++ const char *devtype, const char *inst, ++ const char *var); ++int xenstore_subscribe_to_hotplug_status(struct xs_handle *handle, ++ const char *devtype, ++ const char *inst, ++ const char *token); ++int xenstore_unsubscribe_from_hotplug_status(struct xs_handle *handle, ++ const char *devtype, ++ const char *inst, ++ const char *token); ++ ++ + /* xen_platform.c */ + void pci_xen_platform_init(PCIBus *bus); + diff --git a/tools/ioemu/patches/xenstore-write-vnc-port b/tools/ioemu/patches/xenstore-write-vnc-port index 6db523e980..259d6451f3 100644 --- a/tools/ioemu/patches/xenstore-write-vnc-port +++ b/tools/ioemu/patches/xenstore-write-vnc-port @@ -1,7 +1,7 @@ Index: ioemu/xenstore.c =================================================================== ---- ioemu.orig/xenstore.c 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/xenstore.c 2006-10-24 14:33:47.000000000 +0100 +--- ioemu.orig/xenstore.c 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/xenstore.c 2006-12-08 02:02:37.000000000 +0000 @@ -185,3 +185,31 @@ free(image); free(vec); @@ -36,9 +36,9 @@ Index: ioemu/xenstore.c +} Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/vl.c 2006-10-24 14:33:47.000000000 +0100 -@@ -6550,6 +6550,7 @@ +--- ioemu.orig/vl.c 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 02:02:37.000000000 +0000 +@@ -6535,6 +6535,7 @@ vnc_display = vnc_display_init(ds, vnc_display, vncunused, &vnclisten_addr); if (vncviewer) vnc_start_viewer(vnc_display); @@ -48,8 +48,8 @@ Index: ioemu/vl.c sdl_display_init(ds, full_screen); Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-10-24 14:33:47.000000000 +0100 -+++ ioemu/vl.h 2006-10-24 14:33:47.000000000 +0100 +--- ioemu.orig/vl.h 2006-12-08 02:02:37.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 02:02:37.000000000 +0000 @@ -1210,6 +1210,7 @@ int xenstore_fd(void); void xenstore_process_event(void *opaque); From 8f83b7e2ea1961c0bd712e1a4c64ef39ba1b5a96 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild2.aw" Date: Fri, 8 Dec 2006 11:31:29 -0700 Subject: [PATCH 276/282] [IA64] avoid freeing arch.privregs twice Not sure how this worked before, but mapping vcpu regs into guest pseudo phys space causes extra problems. Signed-off-by: Alex Williamson --- xen/arch/ia64/xen/dom0_ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index e0aaff58d6..e21c96f827 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -109,6 +109,7 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) BUG_ON(v->arch.privregs == NULL); free_domheap_pages(virt_to_page(v->arch.privregs), get_order_from_shift(XMAPPEDREGS_SHIFT)); + v->arch.privregs = NULL; relinquish_vcpu_resources(v); } } From a456fc76663cbbbcc2cfbb34935e538189290ef3 Mon Sep 17 00:00:00 2001 From: Christian Limpach Date: Fri, 8 Dec 2006 18:37:19 +0000 Subject: [PATCH 277/282] [qemu patches] Update patches upto changeset 12814:c3ad3fcfe3. Signed-off-by: Christian Limpach --- tools/ioemu/patches/domain-timeoffset | 16 +- tools/ioemu/patches/series | 2 + tools/ioemu/patches/tpm-tis-device | 28 +- .../patches/usb-mouse-tablet-status-check | 168 ++++++++++ tools/ioemu/patches/xen-mapcache | 300 ++++++++++++++++++ 5 files changed, 495 insertions(+), 19 deletions(-) create mode 100644 tools/ioemu/patches/usb-mouse-tablet-status-check create mode 100644 tools/ioemu/patches/xen-mapcache diff --git a/tools/ioemu/patches/domain-timeoffset b/tools/ioemu/patches/domain-timeoffset index f91a61a37a..45e081381d 100644 --- a/tools/ioemu/patches/domain-timeoffset +++ b/tools/ioemu/patches/domain-timeoffset @@ -1,7 +1,7 @@ Index: ioemu/hw/mc146818rtc.c =================================================================== ---- ioemu.orig/hw/mc146818rtc.c 2006-12-08 18:23:40.000000000 +0000 -+++ ioemu/hw/mc146818rtc.c 2006-12-08 18:23:46.000000000 +0000 +--- ioemu.orig/hw/mc146818rtc.c 2006-12-08 18:36:31.000000000 +0000 ++++ ioemu/hw/mc146818rtc.c 2006-12-08 18:36:36.000000000 +0000 @@ -178,10 +178,27 @@ } } @@ -46,8 +46,8 @@ Index: ioemu/hw/mc146818rtc.c static void rtc_copy_date(RTCState *s) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-12-08 18:23:46.000000000 +0000 -+++ ioemu/hw/pc.c 2006-12-08 18:23:46.000000000 +0000 +--- ioemu.orig/hw/pc.c 2006-12-08 18:36:35.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 18:36:36.000000000 +0000 @@ -159,7 +159,7 @@ } @@ -117,8 +117,8 @@ Index: ioemu/hw/pc.c QEMUMachine pc_machine = { Index: ioemu/vl.c =================================================================== ---- ioemu.orig/vl.c 2006-12-08 18:23:46.000000000 +0000 -+++ ioemu/vl.c 2006-12-08 18:23:46.000000000 +0000 +--- ioemu.orig/vl.c 2006-12-08 18:36:35.000000000 +0000 ++++ ioemu/vl.c 2006-12-08 18:36:36.000000000 +0000 @@ -163,6 +163,8 @@ int xc_handle; @@ -174,8 +174,8 @@ Index: ioemu/vl.c if (usb_enabled) { Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-12-08 18:23:46.000000000 +0000 -+++ ioemu/vl.h 2006-12-08 18:23:46.000000000 +0000 +--- ioemu.orig/vl.h 2006-12-08 18:36:35.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:36:36.000000000 +0000 @@ -576,7 +576,7 @@ int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, diff --git a/tools/ioemu/patches/series b/tools/ioemu/patches/series index 0b92ba302f..6d6f1f8ee6 100644 --- a/tools/ioemu/patches/series +++ b/tools/ioemu/patches/series @@ -67,3 +67,5 @@ usb-uhci-buffer-size vnc-monitor-shift-key-processing ide-error-reporting vnc-numpad-handling +xen-mapcache -p3 +usb-mouse-tablet-status-check -p3 diff --git a/tools/ioemu/patches/tpm-tis-device b/tools/ioemu/patches/tpm-tis-device index 5b5acc7b92..f0b4c00858 100644 --- a/tools/ioemu/patches/tpm-tis-device +++ b/tools/ioemu/patches/tpm-tis-device @@ -22,8 +22,8 @@ Signed-off-by: Stefan Berger Index: ioemu/Makefile.target =================================================================== ---- ioemu.orig/Makefile.target 2006-12-08 18:20:53.000000000 +0000 -+++ ioemu/Makefile.target 2006-12-08 18:21:18.000000000 +0000 +--- ioemu.orig/Makefile.target 2006-12-08 18:33:48.000000000 +0000 ++++ ioemu/Makefile.target 2006-12-08 18:35:14.000000000 +0000 @@ -369,6 +369,7 @@ VL_OBJS+= piix4acpi.o VL_OBJS+= xenstore.o @@ -34,8 +34,8 @@ Index: ioemu/Makefile.target ifeq ($(TARGET_BASE_ARCH), ppc) Index: ioemu/hw/pc.c =================================================================== ---- ioemu.orig/hw/pc.c 2006-12-08 18:20:52.000000000 +0000 -+++ ioemu/hw/pc.c 2006-12-08 18:21:18.000000000 +0000 +--- ioemu.orig/hw/pc.c 2006-12-08 18:33:47.000000000 +0000 ++++ ioemu/hw/pc.c 2006-12-08 18:33:48.000000000 +0000 @@ -875,6 +875,9 @@ } } @@ -49,8 +49,8 @@ Index: ioemu/hw/pc.c Index: ioemu/hw/tpm_tis.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ ioemu/hw/tpm_tis.c 2006-12-08 18:21:18.000000000 +0000 -@@ -0,0 +1,1114 @@ ++++ ioemu/hw/tpm_tis.c 2006-12-08 18:35:25.000000000 +0000 +@@ -0,0 +1,1120 @@ +/* + * tpm_tis.c - QEMU emulator for a 1.2 TPM with TIS interface + * @@ -185,7 +185,7 @@ Index: ioemu/hw/tpm_tis.c + + +/* local prototypes */ -+static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg); ++static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg); +static int TPM_Receive(tpmState *s, tpmBuffer *buffer); +static uint32_t vtpm_instance_from_xenstore(void); +static void tis_poll_timer(void *opaque); @@ -324,6 +324,8 @@ Index: ioemu/hw/tpm_tis.c +/* + * the 'write' method for sending requests to the vTPM + * four bytes with the vTPM instance number are prepended to each request ++ * the locality in which the command was sent is transmitted in the ++ * highest 3 bits + */ +static int write_local_socket(tpmState *s, const tpmBuffer *buffer) +{ @@ -661,7 +663,7 @@ Index: ioemu/hw/tpm_tis.c + } + } + if (val & STS_TPM_GO) { -+ n = TPM_Send(s, &s->buffer,"tpm_data_write"); ++ n = TPM_Send(s, &s->buffer, locty, "tpm_data_write"); + if (n > 0) { + /* sending of data was successful */ + s->offset = 0; @@ -968,7 +970,7 @@ Index: ioemu/hw/tpm_tis.c +/* + * Send a TPM request. + */ -+static int TPM_Send(tpmState *s, tpmBuffer *buffer, char *msg) ++static int TPM_Send(tpmState *s, tpmBuffer *buffer, uint8_t locty, char *msg) +{ + int len; + uint32_t size = tpm_get_size_from_buffer(buffer->buf); @@ -998,6 +1000,10 @@ Index: ioemu/hw/tpm_tis.c + showBuff(buffer->buf, "To TPM"); +#endif + ++ /* transmit the locality in the highest 3 bits */ ++ buffer->instance[0] &= 0x1f; ++ buffer->instance[0] |= (locty << 5); ++ + len = vTPMTransmit[s->Transmitlayer].write(s, buffer); + if (len < 0) { + s->Transmitlayer = -1; @@ -1167,8 +1173,8 @@ Index: ioemu/hw/tpm_tis.c +} Index: ioemu/vl.h =================================================================== ---- ioemu.orig/vl.h 2006-12-08 18:20:53.000000000 +0000 -+++ ioemu/vl.h 2006-12-08 18:21:18.000000000 +0000 +--- ioemu.orig/vl.h 2006-12-08 18:33:48.000000000 +0000 ++++ ioemu/vl.h 2006-12-08 18:35:14.000000000 +0000 @@ -932,6 +932,10 @@ void piix4_pm_init(PCIBus *bus, int devfn); void acpi_bios_init(void); diff --git a/tools/ioemu/patches/usb-mouse-tablet-status-check b/tools/ioemu/patches/usb-mouse-tablet-status-check new file mode 100644 index 0000000000..6047523fea --- /dev/null +++ b/tools/ioemu/patches/usb-mouse-tablet-status-check @@ -0,0 +1,168 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID 60bbcf799384d779c2a561b9d9ba30f28e31d970 +# Parent fb3cb6f52a2905be938559529ae43b6ba990c878 +[HVM] qemu mouse: Adds support for USB mouse/tablet status check and +restricts Universal Host Controller interrupt generating when received +NAK in interrupt transfer. + +According to usb spec, USB mouse/tablet device returns NAK to host +controller if its status does not alter in interrupt transfer. +And UHC should leave a TD active when receiving NAK and execute this +incompleted TD in a subseqent frame. UHC only generates an interrupt +on complete after the TD with ICO bit is completed. + +This patch make UHC & USB mouse/tablet behave consistently with spec. + +Signed-off-by: Xinmei Huang + +diff -r fb3cb6f52a29 -r 60bbcf799384 tools/ioemu/hw/usb-hid.c +--- a/tools/ioemu/hw/usb-hid.c Thu Dec 07 11:51:22 2006 +0000 ++++ b/tools/ioemu/hw/usb-hid.c Thu Dec 07 11:52:26 2006 +0000 +@@ -39,6 +39,7 @@ typedef struct USBMouseState { + int x, y; + int kind; + int mouse_grabbed; ++ int status_changed; + } USBMouseState; + + /* mostly the same values as the Bochs USB Mouse device */ +@@ -231,6 +232,7 @@ static void usb_mouse_event(void *opaque + s->dy += dy1; + s->dz += dz1; + s->buttons_state = buttons_state; ++ s->status_changed = 1; + } + + static void usb_tablet_event(void *opaque, +@@ -242,6 +244,7 @@ static void usb_tablet_event(void *opaqu + s->y = y; + s->dz += dz; + s->buttons_state = buttons_state; ++ s->status_changed = 1; + } + + static inline int int_clamp(int val, int vmin, int vmax) +@@ -483,10 +486,16 @@ static int usb_mouse_handle_data(USBDevi + switch(pid) { + case USB_TOKEN_IN: + if (devep == 1) { +- if (s->kind == USB_MOUSE) +- ret = usb_mouse_poll(s, data, len); +- else if (s->kind == USB_TABLET) +- ret = usb_tablet_poll(s, data, len); ++ if (s->kind == USB_MOUSE) ++ ret = usb_mouse_poll(s, data, len); ++ else if (s->kind == USB_TABLET) ++ ret = usb_tablet_poll(s, data, len); ++ ++ if (!s->status_changed) ++ ret = USB_RET_NAK; ++ else ++ s->status_changed = 0; ++ + } else { + goto fail; + } +@@ -523,6 +532,7 @@ USBDevice *usb_tablet_init(void) + s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; + s->kind = USB_TABLET; ++ s->status_changed = 0; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet"); + +@@ -544,6 +554,7 @@ USBDevice *usb_mouse_init(void) + s->dev.handle_data = usb_mouse_handle_data; + s->dev.handle_destroy = usb_mouse_handle_destroy; + s->kind = USB_MOUSE; ++ s->status_changed = 0; + + pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse"); + +diff -r fb3cb6f52a29 -r 60bbcf799384 tools/ioemu/hw/usb-uhci.c +--- a/tools/ioemu/hw/usb-uhci.c Thu Dec 07 11:51:22 2006 +0000 ++++ b/tools/ioemu/hw/usb-uhci.c Thu Dec 07 11:52:26 2006 +0000 +@@ -424,12 +424,10 @@ static int uhci_handle_td(UHCIState *s, + uint8_t buf[2048]; + int len, max_len, err, ret; + +- if (td->ctrl & TD_CTRL_IOC) { +- *int_mask |= 0x01; +- } +- +- if (!(td->ctrl & TD_CTRL_ACTIVE)) +- return 1; ++ if (!(td->ctrl & TD_CTRL_ACTIVE)){ ++ ret = 1; ++ goto out; ++ } + + /* TD is active */ + max_len = ((td->token >> 21) + 1) & 0x7ff; +@@ -467,7 +465,8 @@ static int uhci_handle_td(UHCIState *s, + /* invalid pid : frame interrupted */ + s->status |= UHCI_STS_HCPERR; + uhci_update_irq(s); +- return -1; ++ ret = -1; ++ goto out; + } + if (td->ctrl & TD_CTRL_IOS) + td->ctrl &= ~TD_CTRL_ACTIVE; +@@ -479,10 +478,12 @@ static int uhci_handle_td(UHCIState *s, + len < max_len) { + *int_mask |= 0x02; + /* short packet: do not update QH */ +- return 1; ++ ret = 1; ++ goto out; + } else { + /* success */ +- return 0; ++ ret = 0; ++ goto out; + } + } else { + switch(ret) { +@@ -501,23 +502,34 @@ static int uhci_handle_td(UHCIState *s, + } + td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | + (err << TD_CTRL_ERROR_SHIFT); +- return 1; ++ ret = 1; ++ goto out; + case USB_RET_NAK: + td->ctrl |= TD_CTRL_NAK; + if (pid == USB_TOKEN_SETUP) + goto do_timeout; +- return 1; ++ ret = 1; ++ goto out; + case USB_RET_STALL: + td->ctrl |= TD_CTRL_STALL; + td->ctrl &= ~TD_CTRL_ACTIVE; +- return 1; ++ ret = 1; ++ goto out; + case USB_RET_BABBLE: + td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; + td->ctrl &= ~TD_CTRL_ACTIVE; + /* frame interrupted */ +- return -1; +- } +- } ++ ret = -1; ++ goto out; ++ } ++ } ++ ++out: ++ /* If TD is inactive and IOC bit set to 1 then update int_mask */ ++ if ((td->ctrl & TD_CTRL_IOC) && (!(td->ctrl & TD_CTRL_ACTIVE))) { ++ *int_mask |= 0x01; ++ } ++ return ret; + } + + static void uhci_frame_timer(void *opaque) diff --git a/tools/ioemu/patches/xen-mapcache b/tools/ioemu/patches/xen-mapcache new file mode 100644 index 0000000000..dc37d662a7 --- /dev/null +++ b/tools/ioemu/patches/xen-mapcache @@ -0,0 +1,300 @@ +# HG changeset patch +# User kfraser@localhost.localdomain +# Node ID 67a06a9b7b1dca707e1cd3b08ae0a341d6e97b3d +# Parent 3f0ca90351e268084fbdb733d70fc596cb46537d +[HVM] qemu: Add guest address-space mapping cache. + +On IA32 host or IA32 PAE host, at present, generally, we can't create +an HVM guest with more than 2G memory, because generally it's almost +impossible for Qemu to find a large enough and consecutive virtual +address space to map an HVM guest's whole physical address space. +The attached patch fixes this issue using dynamic mapping based on +little blocks of memory. + +Signed-off-by: Jun Nakajima +Signed-off-by: Dexuan Cui +Signed-off-by: Keir Fraser + +diff -r 3f0ca90351e2 -r 67a06a9b7b1d tools/ioemu/target-i386-dm/cpu.h +--- a/tools/ioemu/target-i386-dm/cpu.h Thu Dec 07 10:54:43 2006 +0000 ++++ b/tools/ioemu/target-i386-dm/cpu.h Thu Dec 07 11:12:52 2006 +0000 +@@ -25,7 +25,8 @@ + #ifdef TARGET_X86_64 + #define TARGET_LONG_BITS 64 + #else +-#define TARGET_LONG_BITS 32 ++/* #define TARGET_LONG_BITS 32 */ ++#define TARGET_LONG_BITS 64 /* for Qemu map cache */ + #endif + + /* target supports implicit self modifying code */ +diff -r 3f0ca90351e2 -r 67a06a9b7b1d tools/ioemu/target-i386-dm/exec-dm.c +--- a/tools/ioemu/target-i386-dm/exec-dm.c Thu Dec 07 10:54:43 2006 +0000 ++++ b/tools/ioemu/target-i386-dm/exec-dm.c Thu Dec 07 11:12:52 2006 +0000 +@@ -36,6 +36,7 @@ + + #include "cpu.h" + #include "exec-all.h" ++#include "vl.h" + + //#define DEBUG_TB_INVALIDATE + //#define DEBUG_FLUSH +@@ -426,6 +427,12 @@ static inline int paddr_is_ram(target_ph + #endif + } + ++#if defined(__i386__) || defined(__x86_64__) ++#define phys_ram_addr(x) (qemu_map_cache(x)) ++#elif defined(__ia64__) ++#define phys_ram_addr(x) (phys_ram_base + (x)) ++#endif ++ + void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, + int len, int is_write) + { +@@ -438,7 +445,7 @@ void cpu_physical_memory_rw(target_phys_ + l = TARGET_PAGE_SIZE - (addr & ~TARGET_PAGE_MASK); + if (l > len) + l = len; +- ++ + io_index = iomem_index(addr); + if (is_write) { + if (io_index) { +@@ -460,9 +467,10 @@ void cpu_physical_memory_rw(target_phys_ + } + } else if (paddr_is_ram(addr)) { + /* Reading from RAM */ +- memcpy(phys_ram_base + addr, buf, l); ++ ptr = phys_ram_addr(addr); ++ memcpy(ptr, buf, l); + #ifdef __ia64__ +- sync_icache((unsigned long)(phys_ram_base + addr), l); ++ sync_icache(ptr, l); + #endif + } + } else { +@@ -485,7 +493,8 @@ void cpu_physical_memory_rw(target_phys_ + } + } else if (paddr_is_ram(addr)) { + /* Reading from RAM */ +- memcpy(buf, phys_ram_base + addr, l); ++ ptr = phys_ram_addr(addr); ++ memcpy(buf, ptr, l); + } else { + /* Neither RAM nor known MMIO space */ + memset(buf, 0xff, len); +diff -r 3f0ca90351e2 -r 67a06a9b7b1d tools/ioemu/vl.c +--- a/tools/ioemu/vl.c Thu Dec 07 10:54:43 2006 +0000 ++++ b/tools/ioemu/vl.c Thu Dec 07 11:12:52 2006 +0000 +@@ -5807,6 +5807,92 @@ int set_mm_mapping(int xc_handle, uint32 + + return 0; + } ++ ++#if defined(__i386__) || defined(__x86_64__) ++static struct map_cache *mapcache_entry; ++static unsigned long nr_buckets; ++ ++static int qemu_map_cache_init(unsigned long nr_pages) ++{ ++ unsigned long max_pages = MAX_MCACHE_SIZE >> PAGE_SHIFT; ++ int i; ++ ++ if (nr_pages < max_pages) ++ max_pages = nr_pages; ++ ++ nr_buckets = (max_pages << PAGE_SHIFT) >> MCACHE_BUCKET_SHIFT; ++ ++ fprintf(logfile, "qemu_map_cache_init nr_buckets = %lx\n", nr_buckets); ++ ++ mapcache_entry = malloc(nr_buckets * sizeof(struct map_cache)); ++ if (mapcache_entry == NULL) { ++ errno = ENOMEM; ++ return -1; ++ } ++ ++ memset(mapcache_entry, 0, nr_buckets * sizeof(struct map_cache)); ++ ++ /* ++ * To avoid ENOMEM from xc_map_foreign_batch() at runtime, we ++ * pre-fill all the map caches in advance. ++ */ ++ for (i = 0; i < nr_buckets; i++) ++ (void)qemu_map_cache(((target_phys_addr_t)i) << MCACHE_BUCKET_SHIFT); ++ ++ return 0; ++} ++ ++uint8_t *qemu_map_cache(target_phys_addr_t phys_addr) ++{ ++ struct map_cache *entry; ++ unsigned long address_index = phys_addr >> MCACHE_BUCKET_SHIFT; ++ unsigned long address_offset = phys_addr & (MCACHE_BUCKET_SIZE-1); ++ ++ /* For most cases (>99.9%), the page address is the same. */ ++ static unsigned long last_address_index = ~0UL; ++ static uint8_t *last_address_vaddr; ++ ++ if (address_index == last_address_index) ++ return last_address_vaddr + address_offset; ++ ++ entry = &mapcache_entry[address_index % nr_buckets]; ++ ++ if (entry->vaddr_base == NULL || entry->paddr_index != address_index) ++ { ++ /* We need to remap a bucket. */ ++ uint8_t *vaddr_base; ++ unsigned long pfns[MCACHE_BUCKET_SIZE >> PAGE_SHIFT]; ++ unsigned int i; ++ ++ if (entry->vaddr_base != NULL) { ++ errno = munmap(entry->vaddr_base, MCACHE_BUCKET_SIZE); ++ if (errno) { ++ fprintf(logfile, "unmap fails %d\n", errno); ++ exit(-1); ++ } ++ } ++ ++ for (i = 0; i < MCACHE_BUCKET_SIZE >> PAGE_SHIFT; i++) ++ pfns[i] = (address_index << (MCACHE_BUCKET_SHIFT-PAGE_SHIFT)) + i; ++ ++ vaddr_base = xc_map_foreign_batch( ++ xc_handle, domid, PROT_READ|PROT_WRITE, ++ pfns, MCACHE_BUCKET_SIZE >> PAGE_SHIFT); ++ if (vaddr_base == NULL) { ++ fprintf(logfile, "xc_map_foreign_batch error %d\n", errno); ++ exit(-1); ++ } ++ ++ entry->vaddr_base = vaddr_base; ++ entry->paddr_index = address_index;; ++ } ++ ++ last_address_index = address_index; ++ last_address_vaddr = entry->vaddr_base; ++ ++ return last_address_vaddr + address_offset; ++} ++#endif + + int main(int argc, char **argv) + { +@@ -6130,6 +6216,7 @@ int main(int argc, char **argv) + break; + case QEMU_OPTION_m: + ram_size = atol(optarg) * 1024 * 1024; ++ ram_size = (uint64_t)atol(optarg) * 1024 * 1024; + if (ram_size <= 0) + help(); + #ifndef CONFIG_DM +@@ -6400,50 +6487,41 @@ int main(int argc, char **argv) + shared_page_nr = nr_pages - 1; + #endif + ++#if defined(__i386__) || defined(__x86_64__) ++ ++ if ( qemu_map_cache_init(tmp_nr_pages) ) ++ { ++ fprintf(logfile, "qemu_map_cache_init returned: error %d\n", errno); ++ exit(-1); ++ } ++ ++ shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, ++ PROT_READ|PROT_WRITE, shared_page_nr); ++ if (shared_page == NULL) { ++ fprintf(logfile, "map shared IO page returned error %d\n", errno); ++ exit(-1); ++ } ++ ++ fprintf(logfile, "shared page at pfn:%lx\n", shared_page_nr); ++ ++ buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, ++ PROT_READ|PROT_WRITE, ++ shared_page_nr - 2); ++ if (buffered_io_page == NULL) { ++ fprintf(logfile, "map buffered IO page returned error %d\n", errno); ++ exit(-1); ++ } ++ ++ fprintf(logfile, "buffered io page at pfn:%lx\n", shared_page_nr - 2); ++ ++#elif defined(__ia64__) ++ + page_array = (xen_pfn_t *)malloc(tmp_nr_pages * sizeof(xen_pfn_t)); + if (page_array == NULL) { + fprintf(logfile, "malloc returned error %d\n", errno); + exit(-1); + } + +-#if defined(__i386__) || defined(__x86_64__) +- for ( i = 0; i < tmp_nr_pages; i++) +- page_array[i] = i; +- +- phys_ram_base = xc_map_foreign_batch(xc_handle, domid, +- PROT_READ|PROT_WRITE, page_array, +- tmp_nr_pages); +- if (phys_ram_base == NULL) { +- fprintf(logfile, "batch map guest memory returned error %d\n", errno); +- exit(-1); +- } +- +- shared_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, +- PROT_READ|PROT_WRITE, +- page_array[shared_page_nr]); +- if (shared_page == NULL) { +- fprintf(logfile, "map shared IO page returned error %d\n", errno); +- exit(-1); +- } +- +- fprintf(logfile, "shared page at pfn:%lx, mfn: %"PRIx64"\n", +- shared_page_nr, (uint64_t)(page_array[shared_page_nr])); +- +- buffered_io_page = xc_map_foreign_range(xc_handle, domid, PAGE_SIZE, +- PROT_READ|PROT_WRITE, +- page_array[shared_page_nr - 2]); +- if (buffered_io_page == NULL) { +- fprintf(logfile, "map buffered IO page returned error %d\n", errno); +- exit(-1); +- } +- +- fprintf(logfile, "buffered io page at pfn:%lx, mfn: %"PRIx64"\n", +- shared_page_nr - 2, (uint64_t)(page_array[shared_page_nr - 2])); +- +- free(page_array); +- +-#elif defined(__ia64__) +- + if (xc_ia64_get_pfn_list(xc_handle, domid, page_array, + IO_PAGE_START >> PAGE_SHIFT, 3) != 3) { + fprintf(logfile, "xc_ia64_get_pfn_list returned error %d\n", errno); +diff -r 3f0ca90351e2 -r 67a06a9b7b1d tools/ioemu/vl.h +--- a/tools/ioemu/vl.h Thu Dec 07 10:54:43 2006 +0000 ++++ b/tools/ioemu/vl.h Thu Dec 07 11:12:52 2006 +0000 +@@ -156,6 +156,26 @@ extern void *shared_vram; + + extern FILE *logfile; + ++ ++#if defined(__i386__) || defined(__x86_64__) ++#if defined(__i386__) ++#define MAX_MCACHE_SIZE 0x40000000 /* 1GB max for x86 */ ++#define MCACHE_BUCKET_SHIFT 16 ++#elif defined(__x86_64__) ++#define MAX_MCACHE_SIZE 0x1000000000 /* 64GB max for x86_64 */ ++#define MCACHE_BUCKET_SHIFT 20 ++#endif ++ ++#define MCACHE_BUCKET_SIZE (1UL << MCACHE_BUCKET_SHIFT) ++ ++struct map_cache { ++ unsigned long paddr_index; ++ uint8_t *vaddr_base; ++}; ++ ++uint8_t *qemu_map_cache(target_phys_addr_t phys_addr); ++#endif ++ + extern int xc_handle; + extern int domid; + From 5334214febf69d7e84642539543ef5277789cead Mon Sep 17 00:00:00 2001 From: "kaf24@localhost.localdomain" Date: Sat, 9 Dec 2006 15:04:27 +0000 Subject: [PATCH 278/282] pygrub tmp files should live in /var/run/ not /var/lib/, as they are indeed runtime only. Also fix a race condition in making the pygrub fifo. Signed-off-by: John Levon --- tools/pygrub/Makefile | 4 ++-- tools/pygrub/src/pygrub | 6 ++++-- tools/python/xen/xend/XendBootloader.py | 16 +++++++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tools/pygrub/Makefile b/tools/pygrub/Makefile index da75bda4b0..2e7b3e4d21 100644 --- a/tools/pygrub/Makefile +++ b/tools/pygrub/Makefile @@ -12,11 +12,11 @@ build: ifndef XEN_PYTHON_NATIVE_INSTALL install: all CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr" --prefix="" - $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xen + $(INSTALL_DIR) -p $(DESTDIR)/var/run/xend/boot else install: all CC="$(CC)" CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)" - $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xen + $(INSTALL_DIR) -p $(DESTDIR)/var/run/xend/boot endif .PHONY: clean diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub index 64a3662704..8fb43ca680 100644 --- a/tools/pygrub/src/pygrub +++ b/tools/pygrub/src/pygrub @@ -514,14 +514,16 @@ if __name__ == "__main__": fs = fsimage.open(file, offset) kernel = fs.open_file(img.kernel[1],).read() - (tfd, fn) = tempfile.mkstemp(prefix="vmlinuz.", dir="/var/lib/xen") + (tfd, fn) = tempfile.mkstemp(prefix="boot_kernel.", + dir="/var/run/xend/boot") os.write(tfd, kernel) os.close(tfd) sxp = "linux (kernel %s)" %(fn,) if img.initrd: initrd = fs.open_file(img.initrd[1],).read() - (tfd, fn) = tempfile.mkstemp(prefix="initrd.", dir="/var/lib/xen") + (tfd, fn) = tempfile.mkstemp(prefix="boot_ramdisk.", + dir="/var/run/xend/boot") os.write(tfd, initrd) os.close(tfd) sxp += "(ramdisk %s)" %(fn,) diff --git a/tools/python/xen/xend/XendBootloader.py b/tools/python/xen/xend/XendBootloader.py index 879b39806d..48ebb55e66 100644 --- a/tools/python/xen/xend/XendBootloader.py +++ b/tools/python/xen/xend/XendBootloader.py @@ -12,11 +12,12 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -import os, select, errno +import os, select, errno, stat import random import shlex from xen.xend import sxp +from xen.util import mkdir from XendLogging import log from XendError import VmError @@ -37,11 +38,16 @@ def bootloader(blexec, disk, quiet = 0, blargs = None, imgcfg = None): log.error(msg) raise VmError(msg) + mkdir.parents("/var/run/xend/boot/", stat.S_IRWXU) + while True: - fifo = "/var/lib/xen/xenbl.%s" % random.randint(0, 32000) - if not os.path.exists(fifo): - break - os.mkfifo(fifo, 0600) + fifo = "/var/run/xend/boot/xenbl.%s" %(random.randint(0, 32000),) + try: + os.mkfifo(fifo, 0600) + except OSError, e: + if (e.errno != errno.EEXIST): + raise + break child = os.fork() if (not child): From 1daf5e293b8e86eae588d3a515f9aa3d68608319 Mon Sep 17 00:00:00 2001 From: "kaf24@localhost.localdomain" Date: Sat, 9 Dec 2006 16:29:52 +0000 Subject: [PATCH 279/282] [XEN] Shadow-mode-refcount PTE update fix. Add back in support for emulated PTE updates which is critical for shdow_refcount operation. Signed-off-by: Keir Fraser --- xen/arch/x86/mm/shadow/common.c | 326 +++++++++++++++++------------ xen/arch/x86/mm/shadow/multi.c | 20 +- xen/arch/x86/mm/shadow/private.h | 11 +- xen/include/asm-x86/guest_access.h | 16 +- 4 files changed, 216 insertions(+), 157 deletions(-) diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index d554896e83..8ade67b2d4 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -185,15 +185,7 @@ hvm_read(enum x86_segment seg, // In this case, that is only a user vs supervisor access check. // if ( (rc = hvm_copy_from_guest_virt(val, addr, bytes)) == 0 ) - { -#if 0 - struct vcpu *v = current; - SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n", - v->domain->domain_id, v->vcpu_id, - addr, *val, bytes); -#endif return X86EMUL_CONTINUE; - } /* If we got here, there was nothing mapped here, or a bad GFN * was mapped here. This should never happen: we're here because @@ -206,8 +198,190 @@ hvm_read(enum x86_segment seg, return X86EMUL_PROPAGATE_FAULT; } -void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, - struct cpu_user_regs *regs) +static int +hvm_emulate_read(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + return hvm_read(seg, offset, val, bytes, hvm_access_read, + container_of(ctxt, struct sh_emulate_ctxt, ctxt)); +} + +static int +hvm_emulate_insn_fetch(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + unsigned int insn_off = offset - ctxt->regs->eip; + + /* Fall back if requested bytes are not in the prefetch cache. */ + if ( unlikely((insn_off + bytes) > sh_ctxt->insn_buf_bytes) ) + return hvm_read(seg, offset, val, bytes, + hvm_access_insn_fetch, sh_ctxt); + + /* Hit the cache. Simple memcpy. */ + *val = 0; + memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes); + return X86EMUL_CONTINUE; +} + +static int +hvm_emulate_write(enum x86_segment seg, + unsigned long offset, + unsigned long val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + struct vcpu *v = current; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr( + seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); + if ( rc ) + return rc; + + return v->arch.shadow.mode->x86_emulate_write( + v, addr, &val, bytes, sh_ctxt); +} + +static int +hvm_emulate_cmpxchg(enum x86_segment seg, + unsigned long offset, + unsigned long old, + unsigned long new, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + struct vcpu *v = current; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr( + seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); + if ( rc ) + return rc; + + return v->arch.shadow.mode->x86_emulate_cmpxchg( + v, addr, old, new, bytes, sh_ctxt); +} + +static int +hvm_emulate_cmpxchg8b(enum x86_segment seg, + unsigned long offset, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + struct vcpu *v = current; + unsigned long addr; + int rc; + + rc = hvm_translate_linear_addr( + seg, offset, 8, hvm_access_write, sh_ctxt, &addr); + if ( rc ) + return rc; + + return v->arch.shadow.mode->x86_emulate_cmpxchg8b( + v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt); +} + +static struct x86_emulate_ops hvm_shadow_emulator_ops = { + .read = hvm_emulate_read, + .insn_fetch = hvm_emulate_insn_fetch, + .write = hvm_emulate_write, + .cmpxchg = hvm_emulate_cmpxchg, + .cmpxchg8b = hvm_emulate_cmpxchg8b, +}; + +static int +pv_emulate_read(enum x86_segment seg, + unsigned long offset, + unsigned long *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + unsigned int rc; + + *val = 0; + if ( (rc = copy_from_user((void *)val, (void *)offset, bytes)) != 0 ) + { + propagate_page_fault(offset + bytes - rc, 0); /* read fault */ + return X86EMUL_PROPAGATE_FAULT; + } + + return X86EMUL_CONTINUE; +} + +static int +pv_emulate_write(enum x86_segment seg, + unsigned long offset, + unsigned long val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + struct vcpu *v = current; + return v->arch.shadow.mode->x86_emulate_write( + v, offset, &val, bytes, sh_ctxt); +} + +static int +pv_emulate_cmpxchg(enum x86_segment seg, + unsigned long offset, + unsigned long old, + unsigned long new, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + struct vcpu *v = current; + return v->arch.shadow.mode->x86_emulate_cmpxchg( + v, offset, old, new, bytes, sh_ctxt); +} + +static int +pv_emulate_cmpxchg8b(enum x86_segment seg, + unsigned long offset, + unsigned long old_lo, + unsigned long old_hi, + unsigned long new_lo, + unsigned long new_hi, + struct x86_emulate_ctxt *ctxt) +{ + struct sh_emulate_ctxt *sh_ctxt = + container_of(ctxt, struct sh_emulate_ctxt, ctxt); + struct vcpu *v = current; + return v->arch.shadow.mode->x86_emulate_cmpxchg8b( + v, offset, old_lo, old_hi, new_lo, new_hi, sh_ctxt); +} + +static struct x86_emulate_ops pv_shadow_emulator_ops = { + .read = pv_emulate_read, + .insn_fetch = pv_emulate_read, + .write = pv_emulate_write, + .cmpxchg = pv_emulate_cmpxchg, + .cmpxchg8b = pv_emulate_cmpxchg8b, +}; + +struct x86_emulate_ops *shadow_init_emulation( + struct sh_emulate_ctxt *sh_ctxt, struct cpu_user_regs *regs) { struct segment_register *creg; struct vcpu *v = current; @@ -215,6 +389,12 @@ void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, sh_ctxt->ctxt.regs = regs; + if ( !is_hvm_vcpu(v) ) + { + sh_ctxt->ctxt.mode = X86EMUL_MODE_HOST; + return &pv_shadow_emulator_ops; + } + /* Segment cache initialisation. Primed with CS. */ sh_ctxt->valid_seg_regs = 0; creg = hvm_get_seg_reg(x86_seg_cs, sh_ctxt); @@ -237,132 +417,10 @@ void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, !hvm_copy_from_guest_virt( sh_ctxt->insn_buf, addr, sizeof(sh_ctxt->insn_buf))) ? sizeof(sh_ctxt->insn_buf) : 0; + + return &hvm_shadow_emulator_ops; } -static int -sh_x86_emulate_read(enum x86_segment seg, - unsigned long offset, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - return hvm_read(seg, offset, val, bytes, hvm_access_read, - container_of(ctxt, struct sh_emulate_ctxt, ctxt)); -} - -static int -sh_x86_emulate_insn_fetch(enum x86_segment seg, - unsigned long offset, - unsigned long *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); - unsigned int insn_off = offset - ctxt->regs->eip; - - /* Fall back if requested bytes are not in the prefetch cache. */ - if ( unlikely((insn_off + bytes) > sh_ctxt->insn_buf_bytes) ) - return hvm_read(seg, offset, val, bytes, - hvm_access_insn_fetch, sh_ctxt); - - /* Hit the cache. Simple memcpy. */ - *val = 0; - memcpy(val, &sh_ctxt->insn_buf[insn_off], bytes); - return X86EMUL_CONTINUE; -} - -static int -sh_x86_emulate_write(enum x86_segment seg, - unsigned long offset, - unsigned long val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); - struct vcpu *v = current; - unsigned long addr; - int rc; - - rc = hvm_translate_linear_addr( - seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); - if ( rc ) - return rc; - -#if 0 - SHADOW_PRINTK("d=%u v=%u a=%#lx v=%#lx bytes=%u\n", - v->domain->domain_id, v->vcpu_id, addr, val, bytes); -#endif - return v->arch.shadow.mode->x86_emulate_write( - v, addr, &val, bytes, sh_ctxt); -} - -static int -sh_x86_emulate_cmpxchg(enum x86_segment seg, - unsigned long offset, - unsigned long old, - unsigned long new, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) -{ - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); - struct vcpu *v = current; - unsigned long addr; - int rc; - - rc = hvm_translate_linear_addr( - seg, offset, bytes, hvm_access_write, sh_ctxt, &addr); - if ( rc ) - return rc; - -#if 0 - SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx n:=%#lx bytes=%u\n", - v->domain->domain_id, v->vcpu_id, addr, old, new, bytes); -#endif - return v->arch.shadow.mode->x86_emulate_cmpxchg( - v, addr, old, new, bytes, sh_ctxt); -} - -static int -sh_x86_emulate_cmpxchg8b(enum x86_segment seg, - unsigned long offset, - unsigned long old_lo, - unsigned long old_hi, - unsigned long new_lo, - unsigned long new_hi, - struct x86_emulate_ctxt *ctxt) -{ - struct sh_emulate_ctxt *sh_ctxt = - container_of(ctxt, struct sh_emulate_ctxt, ctxt); - struct vcpu *v = current; - unsigned long addr; - int rc; - - rc = hvm_translate_linear_addr( - seg, offset, 8, hvm_access_write, sh_ctxt, &addr); - if ( rc ) - return rc; - -#if 0 - SHADOW_PRINTK("d=%u v=%u a=%#lx o?=%#lx:%lx n:=%#lx:%lx\n", - v->domain->domain_id, v->vcpu_id, addr, old_hi, old_lo, - new_hi, new_lo, ctxt); -#endif - return v->arch.shadow.mode->x86_emulate_cmpxchg8b( - v, addr, old_lo, old_hi, new_lo, new_hi, sh_ctxt); -} - - -struct x86_emulate_ops shadow_emulator_ops = { - .read = sh_x86_emulate_read, - .insn_fetch = sh_x86_emulate_insn_fetch, - .write = sh_x86_emulate_write, - .cmpxchg = sh_x86_emulate_cmpxchg, - .cmpxchg8b = sh_x86_emulate_cmpxchg8b, -}; - /**************************************************************************/ /* Code for "promoting" a guest page to the point where the shadow code is * willing to let it be treated as a guest page table. This generally diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index d9d9bd1c70..d2e7b302ba 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -2585,6 +2585,7 @@ static int sh_page_fault(struct vcpu *v, shadow_l1e_t sl1e, *ptr_sl1e; paddr_t gpa; struct sh_emulate_ctxt emul_ctxt; + struct x86_emulate_ops *emul_ops; int r, mmio; fetch_type_t ft = 0; @@ -2811,13 +2812,14 @@ static int sh_page_fault(struct vcpu *v, return EXCRET_fault_fixed; emulate: - if ( !is_hvm_domain(d) || !guest_mode(regs) ) + if ( !shadow_mode_refcounts(d) || !guest_mode(regs) ) goto not_a_shadow_fault; - hvm_store_cpu_guest_regs(v, regs, NULL); + if ( is_hvm_domain(d) ) + hvm_store_cpu_guest_regs(v, regs, NULL); SHADOW_PRINTK("emulate: eip=%#lx\n", regs->eip); - shadow_init_emulation(&emul_ctxt, regs); + emul_ops = shadow_init_emulation(&emul_ctxt, regs); /* * We do not emulate user writes. Instead we use them as a hint that the @@ -2825,7 +2827,7 @@ static int sh_page_fault(struct vcpu *v, * it seems very unlikely that any OS grants user access to page tables. */ if ( (regs->error_code & PFEC_user_mode) || - x86_emulate_memop(&emul_ctxt.ctxt, &shadow_emulator_ops) ) + x86_emulate_memop(&emul_ctxt.ctxt, emul_ops) ) { SHADOW_PRINTK("emulator failure, unshadowing mfn %#lx\n", mfn_x(gmfn)); @@ -2837,7 +2839,8 @@ static int sh_page_fault(struct vcpu *v, } /* Emulator has changed the user registers: write back */ - hvm_load_cpu_guest_regs(v, regs); + if ( is_hvm_domain(d) ) + hvm_load_cpu_guest_regs(v, regs); goto done; mmio: @@ -3814,9 +3817,10 @@ static inline void * emulate_map_dest(struct vcpu *v, page_fault: errcode |= PFEC_write_access; - if ( ring_3(sh_ctxt->ctxt.regs) ) - errcode |= PFEC_user_mode; - hvm_inject_exception(TRAP_page_fault, errcode, vaddr); + if ( is_hvm_vcpu(v) ) + hvm_inject_exception(TRAP_page_fault, errcode, vaddr); + else + propagate_page_fault(vaddr, errcode); return NULL; } diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h index e5a5796548..6fab2789f9 100644 --- a/xen/arch/x86/mm/shadow/private.h +++ b/xen/arch/x86/mm/shadow/private.h @@ -257,9 +257,6 @@ static inline int sh_type_is_pinnable(struct vcpu *v, unsigned int t) * Various function declarations */ -/* x86 emulator support */ -extern struct x86_emulate_ops shadow_emulator_ops; - /* Hash table functions */ mfn_t shadow_hash_lookup(struct vcpu *v, unsigned long n, unsigned int t); void shadow_hash_insert(struct vcpu *v, @@ -513,17 +510,17 @@ static inline void sh_unpin(struct vcpu *v, mfn_t smfn) struct sh_emulate_ctxt { struct x86_emulate_ctxt ctxt; - /* Cache of up to 15 bytes of instruction. */ + /* [HVM] Cache of up to 15 bytes of instruction. */ uint8_t insn_buf[15]; uint8_t insn_buf_bytes; - /* Cache of segment registers already gathered for this emulation. */ + /* [HVM] Cache of segment registers already gathered for this emulation. */ unsigned int valid_seg_regs; struct segment_register seg_reg[6]; }; -void shadow_init_emulation(struct sh_emulate_ctxt *sh_ctxt, - struct cpu_user_regs *regs); +struct x86_emulate_ops *shadow_init_emulation( + struct sh_emulate_ctxt *sh_ctxt, struct cpu_user_regs *regs); #endif /* _XEN_SHADOW_PRIVATE_H */ diff --git a/xen/include/asm-x86/guest_access.h b/xen/include/asm-x86/guest_access.h index 01e1fa3583..ce5c290787 100644 --- a/xen/include/asm-x86/guest_access.h +++ b/xen/include/asm-x86/guest_access.h @@ -34,7 +34,7 @@ #define copy_to_guest_offset(hnd, off, ptr, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \ copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ }) @@ -46,7 +46,7 @@ #define copy_from_guest_offset(ptr, hnd, off, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_from_user_hvm(_y, _x+(off), sizeof(*_x)*(nr)) :\ copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ }) @@ -55,7 +55,7 @@ #define copy_field_to_guest(hnd, ptr, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_to_user_hvm(_x, _y, sizeof(*_x)) : \ copy_to_user(_x, _y, sizeof(*_x)); \ }) @@ -64,7 +64,7 @@ #define copy_field_from_guest(ptr, hnd, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_from_user_hvm(_y, _x, sizeof(*_x)) : \ copy_from_user(_y, _x, sizeof(*_x)); \ }) @@ -80,7 +80,7 @@ #define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_to_user_hvm(_x+(off), _y, sizeof(*_x)*(nr)) : \ __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ }) @@ -88,7 +88,7 @@ #define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \ const typeof(ptr) _x = (hnd).p; \ const typeof(ptr) _y = (ptr); \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_from_user_hvm(_y, _x+(off),sizeof(*_x)*(nr)) : \ __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ }) @@ -96,7 +96,7 @@ #define __copy_field_to_guest(hnd, ptr, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_to_user_hvm(_x, _y, sizeof(*_x)) : \ __copy_to_user(_x, _y, sizeof(*_x)); \ }) @@ -104,7 +104,7 @@ #define __copy_field_from_guest(ptr, hnd, field) ({ \ const typeof(&(ptr)->field) _x = &(hnd).p->field; \ const typeof(&(ptr)->field) _y = &(ptr)->field; \ - shadow_mode_translate(current->domain) ? \ + is_hvm_vcpu(current) ? \ copy_from_user_hvm(_x, _y, sizeof(*_x)) : \ __copy_from_user(_y, _x, sizeof(*_x)); \ }) From 5eb892022a678d99066febd1ea6b52b0c8739559 Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 11 Dec 2006 09:56:02 +0000 Subject: [PATCH 280/282] [NET] back: Atomic buffer allocations use __GFP_NOWARN. Signed-off-by: Keir Fraser --- linux-2.6-xen-sparse/drivers/xen/netback/netback.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c index f05802aa2e..1884597430 100644 --- a/linux-2.6-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6-xen-sparse/drivers/xen/netback/netback.c @@ -183,7 +183,7 @@ static struct sk_buff *netbk_copy_skb(struct sk_buff *skb) BUG_ON(skb_shinfo(skb)->frag_list != NULL); - nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC); + nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN); if (unlikely(!nskb)) goto err; @@ -1224,7 +1224,8 @@ static void net_tx_action(unsigned long unused) ret < MAX_SKB_FRAGS) ? PKT_PROT_LEN : txreq.size; - skb = alloc_skb(data_len + 16 + NET_IP_ALIGN, GFP_ATOMIC); + skb = alloc_skb(data_len + 16 + NET_IP_ALIGN, + GFP_ATOMIC | __GFP_NOWARN); if (unlikely(skb == NULL)) { DPRINTK("Can't allocate a skb in start_xmit.\n"); netbk_tx_err(netif, &txreq, i); From c4644b811d2b91d8264c4708c4c697713a162ecb Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 11 Dec 2006 11:57:36 +0000 Subject: [PATCH 281/282] [BUILDER] Enable shadow mode for shadow translate guests much earlier. Signed-off-by: Ian Campbell --- tools/libxc/xc_linux_build.c | 164 ++++++++++++++--------------------- 1 file changed, 65 insertions(+), 99 deletions(-) diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c index 8ddb1ed525..7cbd03529b 100644 --- a/tools/libxc/xc_linux_build.c +++ b/tools/libxc/xc_linux_build.c @@ -175,11 +175,10 @@ static int load_initrd(int xc_handle, domid_t dom, return 0; } -#define alloc_pt(ltab, vltab, pltab) \ +#define alloc_pt(ltab, vltab) \ do { \ - pltab = ppt_alloc++; \ - ltab = (uint64_t)page_array[pltab] << PAGE_SHIFT; \ - pltab <<= PAGE_SHIFT; \ + ltab = ppt_alloc++; \ + ltab = (uint64_t)page_array[ltab] << PAGE_SHIFT; \ if ( vltab != NULL ) \ munmap(vltab, PAGE_SIZE); \ if ( (vltab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, \ @@ -202,43 +201,32 @@ static int setup_pg_tables(int xc_handle, uint32_t dom, { l1_pgentry_t *vl1tab=NULL, *vl1e=NULL; l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; - unsigned long l1tab = 0, pl1tab; - unsigned long l2tab = 0, pl2tab; + unsigned long l1tab = 0; + unsigned long l2tab = 0; unsigned long ppt_alloc; unsigned long count; ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT; - alloc_pt(l2tab, vl2tab, pl2tab); + alloc_pt(l2tab, vl2tab); vl2e = &vl2tab[l2_table_offset(dsi_v_start)]; - if (shadow_mode_enabled) - ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl2tab >> PAGE_SHIFT); - else - ctxt->ctrlreg[3] = xen_pfn_to_cr3(l2tab >> PAGE_SHIFT); + ctxt->ctrlreg[3] = xen_pfn_to_cr3(l2tab >> PAGE_SHIFT); for ( count = 0; count < ((v_end - dsi_v_start) >> PAGE_SHIFT); count++ ) { if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) { - alloc_pt(l1tab, vl1tab, pl1tab); + alloc_pt(l1tab, vl1tab); vl1e = &vl1tab[l1_table_offset(dsi_v_start + (count<= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) && (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) ) *vl1e &= ~_PAGE_RW; - } + vl1e++; } munmap(vl1tab, PAGE_SIZE); @@ -266,7 +254,7 @@ static int setup_pg_tables_pae(int xc_handle, uint32_t dom, l1_pgentry_64_t *vl1tab = NULL, *vl1e = NULL; l2_pgentry_64_t *vl2tab = NULL, *vl2e = NULL; l3_pgentry_64_t *vl3tab = NULL, *vl3e = NULL; - uint64_t l1tab, l2tab, l3tab, pl1tab, pl2tab, pl3tab; + uint64_t l1tab, l2tab, l3tab; unsigned long ppt_alloc, count, nmfn; /* First allocate page for page dir. */ @@ -287,12 +275,9 @@ static int setup_pg_tables_pae(int xc_handle, uint32_t dom, page_array[ppt_alloc] = nmfn; } - alloc_pt(l3tab, vl3tab, pl3tab); + alloc_pt(l3tab, vl3tab); vl3e = &vl3tab[l3_table_offset_pae(dsi_v_start)]; - if (shadow_mode_enabled) - ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl3tab >> PAGE_SHIFT); - else - ctxt->ctrlreg[3] = xen_pfn_to_cr3(l3tab >> PAGE_SHIFT); + ctxt->ctrlreg[3] = xen_pfn_to_cr3(l3tab >> PAGE_SHIFT); for ( count = 0; count < ((v_end - dsi_v_start) >> PAGE_SHIFT); count++) { @@ -300,42 +285,33 @@ static int setup_pg_tables_pae(int xc_handle, uint32_t dom, { if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) ) { - alloc_pt(l2tab, vl2tab, pl2tab); + alloc_pt(l2tab, vl2tab); vl2e = &vl2tab[l2_table_offset_pae( dsi_v_start + (count << PAGE_SHIFT))]; - if (shadow_mode_enabled) - *vl3e = pl2tab | L3_PROT; - else - *vl3e++ = l2tab | L3_PROT; + *vl3e++ = l2tab | L3_PROT; } - alloc_pt(l1tab, vl1tab, pl1tab); + alloc_pt(l1tab, vl1tab); vl1e = &vl1tab[l1_table_offset_pae( dsi_v_start + (count << PAGE_SHIFT))]; - if (shadow_mode_enabled) - *vl2e = pl1tab | L2_PROT; - else - *vl2e++ = l1tab | L2_PROT; + *vl2e++ = l1tab | L2_PROT; + } - if ( shadow_mode_enabled ) - { - *vl1e = (count << PAGE_SHIFT) | L1_PROT; - } - else - { - *vl1e = ((uint64_t)page_array[count] << PAGE_SHIFT) | L1_PROT; + *vl1e = ((uint64_t)page_array[count] << PAGE_SHIFT) | L1_PROT; + + if ( !shadow_mode_enabled ) if ( (count >= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) && (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) ) *vl1e &= ~_PAGE_RW; - } + vl1e++; } /* Xen requires a mid-level pgdir mapping 0xC0000000 region. */ if ( (vl3tab[3] & _PAGE_PRESENT) == 0 ) { - alloc_pt(l2tab, vl2tab, pl2tab); + alloc_pt(l2tab, vl2tab); vl3tab[3] = l2tab | L3_PROT; } @@ -371,69 +347,48 @@ static int setup_pg_tables_64(int xc_handle, uint32_t dom, l2_pgentry_t *vl2tab=NULL, *vl2e=NULL; l3_pgentry_t *vl3tab=NULL, *vl3e=NULL; l4_pgentry_t *vl4tab=NULL, *vl4e=NULL; - unsigned long l2tab = 0, pl2tab; - unsigned long l1tab = 0, pl1tab; - unsigned long l3tab = 0, pl3tab; - unsigned long l4tab = 0, pl4tab; + unsigned long l2tab = 0; + unsigned long l1tab = 0; + unsigned long l3tab = 0; + unsigned long l4tab = 0; unsigned long ppt_alloc; unsigned long count; /* First allocate page for page dir. */ ppt_alloc = (vpt_start - dsi_v_start) >> PAGE_SHIFT; - alloc_pt(l4tab, vl4tab, pl4tab); + alloc_pt(l4tab, vl4tab); vl4e = &vl4tab[l4_table_offset(dsi_v_start)]; - if (shadow_mode_enabled) - ctxt->ctrlreg[3] = xen_pfn_to_cr3(pl4tab >> PAGE_SHIFT); - else - ctxt->ctrlreg[3] = xen_pfn_to_cr3(l4tab >> PAGE_SHIFT); + ctxt->ctrlreg[3] = xen_pfn_to_cr3(l4tab >> PAGE_SHIFT); for ( count = 0; count < ((v_end-dsi_v_start)>>PAGE_SHIFT); count++) { if ( !((unsigned long)vl1e & (PAGE_SIZE-1)) ) { - alloc_pt(l1tab, vl1tab, pl1tab); + alloc_pt(l1tab, vl1tab); if ( !((unsigned long)vl2e & (PAGE_SIZE-1)) ) { - alloc_pt(l2tab, vl2tab, pl2tab); + alloc_pt(l2tab, vl2tab); if ( !((unsigned long)vl3e & (PAGE_SIZE-1)) ) { - alloc_pt(l3tab, vl3tab, pl3tab); + alloc_pt(l3tab, vl3tab); vl3e = &vl3tab[l3_table_offset(dsi_v_start + (count<= ((vpt_start-dsi_v_start)>>PAGE_SHIFT)) && (count < ((vpt_end -dsi_v_start)>>PAGE_SHIFT)) ) - { - *vl1e &= ~_PAGE_RW; - } - } + *vl1e &= ~_PAGE_RW; + vl1e++; } @@ -772,6 +727,27 @@ static int setup_guest(int xc_handle, goto error_out; } + + if ( shadow_mode_enabled ) + { + /* + * Enable shadow translate mode. This must happen after + * populate physmap because the p2m reservation is based on + * the domains current memory allocation. + */ + if ( xc_shadow_control(xc_handle, dom, + XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE, + NULL, 0, NULL, 0, NULL) < 0 ) + { + PERROR("Could not enable translation mode"); + goto error_out; + } + + /* Reinitialise the gpfn->gmfn array. */ + for ( i = 0; i < nr_pages; i++ ) + page_array[i] = i; + } + rc = (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array, &dsi); @@ -973,15 +949,6 @@ static int setup_guest(int xc_handle, { struct xen_add_to_physmap xatp; - /* Enable shadow translate mode */ - if ( xc_shadow_control(xc_handle, dom, - XEN_DOMCTL_SHADOW_OP_ENABLE_TRANSLATE, - NULL, 0, NULL, 0, NULL) < 0 ) - { - PERROR("Could not enable translation mode"); - goto error_out; - } - guest_shared_info_mfn = (vsharedinfo_start-dsi.v_start) >> PAGE_SHIFT; /* Map shared info frame into guest physmap. */ @@ -1083,8 +1050,7 @@ static int setup_guest(int xc_handle, if ( pfn >= nr_pages ) goto error_out; domctl.domain = (domid_t)dom; - domctl.u.hypercall_init.gmfn = shadow_mode_enabled ? - pfn : page_array[pfn]; + domctl.u.hypercall_init.gmfn = page_array[pfn]; domctl.cmd = XEN_DOMCTL_hypercall_init; if ( xc_domctl(xc_handle, &domctl) ) goto error_out; From 88008890d4738aef5996d6d79f5a9f58021865bf Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Mon, 11 Dec 2006 15:06:53 +0000 Subject: [PATCH 282/282] [XEN] Remove unnecessary shadow_mode_refcount() code from PV mm code. Signed-off-by: Keir Fraser --- xen/arch/x86/mm.c | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 4fd69400f3..034f992643 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -435,15 +435,6 @@ int map_ldt_shadow_page(unsigned int off) return 0; okay = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page); - - if ( !okay && unlikely(shadow_mode_refcounts(d)) ) - { - shadow_lock(d); - shadow_remove_write_access(d->vcpu[0], _mfn(mfn), 0, 0); - okay = get_page_and_type(mfn_to_page(mfn), d, PGT_ldt_page); - shadow_unlock(d); - } - if ( unlikely(!okay) ) return 0; @@ -509,8 +500,6 @@ get_linear_pagetable( struct page_info *page; unsigned long pfn; - ASSERT( !shadow_mode_refcounts(d) ); - if ( (root_get_flags(re) & _PAGE_RW) ) { MEM_LOG("Attempt to create linear p.t. with write perms"); @@ -821,8 +810,6 @@ static int alloc_l1_table(struct page_info *page) l1_pgentry_t *pl1e; int i; - ASSERT(!shadow_mode_refcounts(d)); - pl1e = map_domain_page(pfn); for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) @@ -873,8 +860,6 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e) * 2. Cannot appear in another page table's L3: * a. alloc_l3_table() calls this function and this check will fail * b. mod_l3_entry() disallows updates to slot 3 in an existing table - * - * XXX -- this needs revisiting for shadow_mode_refcount()==true... */ page = l3e_get_page(l3e3); BUG_ON(page->u.inuse.type_info & PGT_pinned); @@ -959,8 +944,6 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) l2_pgentry_t *pl2e; int i; - ASSERT(!shadow_mode_refcounts(d)); - pl2e = map_domain_page(pfn); for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) @@ -1008,8 +991,6 @@ static int alloc_l3_table(struct page_info *page) l3_pgentry_t *pl3e; int i; - ASSERT(!shadow_mode_refcounts(d)); - #ifdef CONFIG_X86_PAE /* * PAE pgdirs above 4GB are unacceptable if the guest does not understand @@ -1075,8 +1056,6 @@ static int alloc_l4_table(struct page_info *page) l4_pgentry_t *pl4e = page_to_virt(page); int i; - ASSERT(!shadow_mode_refcounts(d)); - for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ ) { if ( is_guest_l4_slot(i) &&