# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1161840396 -32400 # Node ID d1ab7aa092070c9351bc54e601b249110869a59a # Parent 9040d793dedfd53e7079aedf44a1bae6dfc4311e separate xenoprof files in xen into arch-generic/depedent part. implemented dynamic map/unmap xenoprof buffer. this is necessary for IA64 support. PATCHNAME: xenoprof_x86_xen_side Signed-off-by: Isaku Yamahata diff -r 9040d793dedf -r d1ab7aa09207 xen/arch/x86/Rules.mk --- a/xen/arch/x86/Rules.mk Fri Oct 20 21:21:34 2006 +0900 +++ b/xen/arch/x86/Rules.mk Thu Oct 26 14:26:36 2006 +0900 @@ -3,6 +3,7 @@ HAS_ACPI := y HAS_VGA := y +xenoprof := y # # If you change any of these configuration options then you must diff -r 9040d793dedf -r d1ab7aa09207 xen/arch/x86/oprofile/nmi_int.c --- a/xen/arch/x86/oprofile/nmi_int.c Fri Oct 20 21:21:34 2006 +0900 +++ b/xen/arch/x86/oprofile/nmi_int.c Thu Oct 26 14:26:36 2006 +0900 @@ -33,7 +33,6 @@ static unsigned long saved_lvtpc[NR_CPUS #define VIRQ_BITMASK_SIZE (MAX_OPROF_DOMAINS/32 + 1) extern int active_domains[MAX_OPROF_DOMAINS]; extern unsigned int adomains; -extern struct domain *primary_profiler; extern struct domain *adomain_ptrs[MAX_OPROF_DOMAINS]; extern unsigned long virq_ovf_pending[VIRQ_BITMASK_SIZE]; extern int is_active(struct domain *d); @@ -337,10 +336,10 @@ int nmi_init(int *num_events, int *is_pr return -ENODEV; } - if (primary_profiler == NULL) { + if (xenoprof_primary_profiler == NULL) { /* For now, only dom0 can be the primary profiler */ if (current->domain->domain_id == 0) { - primary_profiler = current->domain; + xenoprof_primary_profiler = current->domain; prim = 1; } } diff -r 9040d793dedf -r d1ab7aa09207 xen/arch/x86/oprofile/xenoprof.c --- a/xen/arch/x86/oprofile/xenoprof.c Fri Oct 20 21:21:34 2006 +0900 +++ b/xen/arch/x86/oprofile/xenoprof.c Thu Oct 26 14:26:36 2006 +0900 @@ -2,6 +2,10 @@ * Copyright (C) 2005 Hewlett-Packard Co. * written by Aravind Menon & Jose Renato Santos * (email: xenoprof@xxxxxxxxxxxxx) + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * x86 specific part */ #include @@ -11,689 +15,23 @@ #include "op_counter.h" -/* Limit amount of pages used for shared buffer (per domain) */ -#define MAX_OPROF_SHARED_PAGES 32 +int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_counter counter; + if ( copy_from_guest(&counter, arg, 1) ) + return -EFAULT; -/* Lock protecting the following global state */ -static DEFINE_SPINLOCK(xenoprof_lock); + if ( counter.ind > OP_MAX_COUNTER ) + return -E2BIG; -struct domain *active_domains[MAX_OPROF_DOMAINS]; -int active_ready[MAX_OPROF_DOMAINS]; -unsigned int adomains; - -struct domain *passive_domains[MAX_OPROF_DOMAINS]; -unsigned int pdomains; - -unsigned int activated; -struct domain *primary_profiler; -int xenoprof_state = XENOPROF_IDLE; - -u64 total_samples; -u64 invalid_buffer_samples; -u64 corrupted_buffer_samples; -u64 lost_samples; -u64 active_samples; -u64 passive_samples; -u64 idle_samples; -u64 others_samples; - - -extern int nmi_init(int *num_events, int *is_primary, char *cpu_type); -extern int nmi_reserve_counters(void); -extern int nmi_setup_events(void); -extern int nmi_enable_virq(void); -extern int nmi_start(void); -extern void nmi_stop(void); -extern void nmi_disable_virq(void); -extern void nmi_release_counters(void); - -int is_active(struct domain *d) -{ - struct xenoprof *x = d->xenoprof; - return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE)); -} - -int is_passive(struct domain *d) -{ - struct xenoprof *x = d->xenoprof; - return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE)); -} - -int is_profiled(struct domain *d) -{ - return (is_active(d) || is_passive(d)); -} - -static void xenoprof_reset_stat(void) -{ - total_samples = 0; - invalid_buffer_samples = 0; - corrupted_buffer_samples = 0; - lost_samples = 0; - active_samples = 0; - passive_samples = 0; - idle_samples = 0; - others_samples = 0; -} - -static void xenoprof_reset_buf(struct domain *d) -{ - int j; - struct xenoprof_buf *buf; - - if ( d->xenoprof == NULL ) - { - printk("xenoprof_reset_buf: ERROR - Unexpected " - "Xenoprof NULL pointer \n"); - return; - } - - for ( j = 0; j < MAX_VIRT_CPUS; j++ ) - { - buf = d->xenoprof->vcpu[j].buffer; - if ( buf != NULL ) - { - buf->event_head = 0; - buf->event_tail = 0; - } - } -} - -static char *alloc_xenoprof_buf(struct domain *d, int npages) -{ - char *rawbuf; - int i, order; - - /* allocate pages to store sample buffer shared with domain */ - order = get_order_from_pages(npages); - rawbuf = alloc_xenheap_pages(order); - if ( rawbuf == NULL ) - { - printk("alloc_xenoprof_buf(): memory allocation failed\n"); - return 0; - } - - /* Share pages so that kernel can map it */ - for ( i = 0; i < npages; i++ ) - share_xen_page_with_guest( - virt_to_page(rawbuf + i * PAGE_SIZE), - d, XENSHARE_writable); - - return rawbuf; -} - -static int alloc_xenoprof_struct( - struct domain *d, int max_samples, int is_passive) -{ - struct vcpu *v; - int nvcpu, npages, bufsize, max_bufsize; - unsigned max_max_samples; - int i; - - d->xenoprof = xmalloc(struct xenoprof); - - if ( d->xenoprof == NULL ) - { - printk ("alloc_xenoprof_struct(): memory " - "allocation (xmalloc) failed\n"); - return -ENOMEM; - } - - memset(d->xenoprof, 0, sizeof(*d->xenoprof)); - - nvcpu = 0; - for_each_vcpu ( d, v ) - nvcpu++; - - /* reduce max_samples if necessary to limit pages allocated */ - max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu; - max_max_samples = ( (max_bufsize - sizeof(struct xenoprof_buf)) / - sizeof(struct event_log) ) + 1; - if ( (unsigned)max_samples > max_max_samples ) - max_samples = max_max_samples; - - bufsize = sizeof(struct xenoprof_buf) + - (max_samples - 1) * sizeof(struct event_log); - npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1; - - d->xenoprof->rawbuf = alloc_xenoprof_buf(is_passive ? dom0 : d, npages); - - if ( d->xenoprof->rawbuf == NULL ) - { - xfree(d->xenoprof); - d->xenoprof = NULL; - return -ENOMEM; - } - - d->xenoprof->npages = npages; - d->xenoprof->nbuf = nvcpu; - d->xenoprof->bufsize = bufsize; - d->xenoprof->domain_ready = 0; - d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; - - /* Update buffer pointers for active vcpus */ - i = 0; - for_each_vcpu ( d, v ) - { - d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples; - d->xenoprof->vcpu[v->vcpu_id].buffer = - (struct xenoprof_buf *)&d->xenoprof->rawbuf[i * bufsize]; - d->xenoprof->vcpu[v->vcpu_id].buffer->event_size = max_samples; - d->xenoprof->vcpu[v->vcpu_id].buffer->vcpu_id = v->vcpu_id; - - i++; - /* in the unlikely case that the number of active vcpus changes */ - if ( i >= nvcpu ) - break; - } - - return 0; -} - -void free_xenoprof_pages(struct domain *d) -{ - struct xenoprof *x; - int order; - - x = d->xenoprof; - if ( x == NULL ) - return; - - if ( x->rawbuf != NULL ) - { - order = get_order_from_pages(x->npages); - free_xenheap_pages(x->rawbuf, order); - } - - xfree(x); - d->xenoprof = NULL; -} - -static int active_index(struct domain *d) -{ - int i; - - for ( i = 0; i < adomains; i++ ) - if ( active_domains[i] == d ) - return i; - - return -1; -} - -static int set_active(struct domain *d) -{ - int ind; - struct xenoprof *x; - - ind = active_index(d); - if ( ind < 0 ) - return -EPERM; - - x = d->xenoprof; - if ( x == NULL ) - return -EPERM; - - x->domain_ready = 1; - x->domain_type = XENOPROF_DOMAIN_ACTIVE; - active_ready[ind] = 1; - activated++; + counter_config[counter.ind].count = (unsigned long) counter.count; + counter_config[counter.ind].enabled = (unsigned long) counter.enabled; + counter_config[counter.ind].event = (unsigned long) counter.event; + counter_config[counter.ind].kernel = (unsigned long) counter.kernel; + counter_config[counter.ind].user = (unsigned long) counter.user; + counter_config[counter.ind].unit_mask = (unsigned long) counter.unit_mask; return 0; -} - -static int reset_active(struct domain *d) -{ - int ind; - struct xenoprof *x; - - ind = active_index(d); - if ( ind < 0 ) - return -EPERM; - - x = d->xenoprof; - if ( x == NULL ) - return -EPERM; - - x->domain_ready = 0; - x->domain_type = XENOPROF_DOMAIN_IGNORED; - active_ready[ind] = 0; - active_domains[ind] = NULL; - activated--; - put_domain(d); - - if ( activated <= 0 ) - adomains = 0; - - return 0; -} - -static void reset_passive(struct domain *d) -{ - struct xenoprof *x; - - if (d==0) - return; - - x = d->xenoprof; - if ( x == NULL ) - return; - - x->domain_type = XENOPROF_DOMAIN_IGNORED; - - return; -} - -static void reset_active_list(void) -{ - int i; - - for ( i = 0; i < adomains; i++ ) - { - if ( active_ready[i] ) - { - reset_active(active_domains[i]); - } - } - - adomains = 0; - activated = 0; -} - -static void reset_passive_list(void) -{ - int i; - - for ( i = 0; i < pdomains; i++ ) - { - reset_passive(passive_domains[i]); - put_domain(passive_domains[i]); - passive_domains[i] = NULL; - } - - pdomains = 0; -} - -static int add_active_list(domid_t domid) -{ - struct domain *d; - - if ( adomains >= MAX_OPROF_DOMAINS ) - return -E2BIG; - - d = find_domain_by_id(domid); - if ( d == NULL ) - return -EINVAL; - - active_domains[adomains] = d; - active_ready[adomains] = 0; - adomains++; - - return 0; -} - -static int add_passive_list(XEN_GUEST_HANDLE(void) arg) -{ - struct xenoprof_passive passive; - struct domain *d; - int ret = 0; - - if ( pdomains >= MAX_OPROF_DOMAINS ) - return -E2BIG; - - if ( copy_from_guest(&passive, arg, 1) ) - return -EFAULT; - - d = find_domain_by_id(passive.domain_id); - if ( d == NULL ) - return -EINVAL; - - if ( (d->xenoprof == NULL) && - ((ret = alloc_xenoprof_struct(d, passive.max_samples, 1)) < 0) ) { - put_domain(d); - return -ENOMEM; - } - - d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE; - passive.nbuf = d->xenoprof->nbuf; - passive.bufsize = d->xenoprof->bufsize; - passive.buf_maddr = __pa(d->xenoprof->rawbuf); - - if ( copy_to_guest(arg, &passive, 1) ) { - put_domain(d); - return -EFAULT; - } - - passive_domains[pdomains] = d; - pdomains++; - - return ret; -} - -void xenoprof_log_event( - struct vcpu *vcpu, unsigned long eip, int mode, int event) -{ - struct xenoprof_vcpu *v; - struct xenoprof_buf *buf; - int head; - int tail; - int size; - - - total_samples++; - - /* ignore samples of un-monitored domains */ - /* Count samples in idle separate from other unmonitored domains */ - if ( !is_profiled(vcpu->domain) ) - { - others_samples++; - return; - } - - v = &vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id]; - - /* Sanity check. Should never happen */ - if ( v->buffer == NULL ) - { - invalid_buffer_samples++; - return; - } - - buf = vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id].buffer; - - head = buf->event_head; - tail = buf->event_tail; - size = v->event_size; - - /* make sure indexes in shared buffer are sane */ - if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) ) - { - corrupted_buffer_samples++; - return; - } - - if ( (head == tail - 1) || (head == size - 1 && tail == 0) ) - { - buf->lost_samples++; - lost_samples++; - } - else - { - buf->event_log[head].eip = eip; - buf->event_log[head].mode = mode; - buf->event_log[head].event = event; - head++; - if ( head >= size ) - head = 0; - buf->event_head = head; - if ( is_active(vcpu->domain) ) - active_samples++; - else - passive_samples++; - if ( mode == 0 ) - buf->user_samples++; - else if ( mode == 1 ) - buf->kernel_samples++; - else - buf->xen_samples++; - } -} - -static int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg) -{ - struct xenoprof_init xenoprof_init; - int ret; - - if ( copy_from_guest(&xenoprof_init, arg, 1) ) - return -EFAULT; - - if ( (ret = nmi_init(&xenoprof_init.num_events, - &xenoprof_init.is_primary, - xenoprof_init.cpu_type)) ) - return ret; - - if ( copy_to_guest(arg, &xenoprof_init, 1) ) - return -EFAULT; - - if ( xenoprof_init.is_primary ) - primary_profiler = current->domain; - - return 0; -} - -static int xenoprof_op_get_buffer(XEN_GUEST_HANDLE(void) arg) -{ - struct xenoprof_get_buffer xenoprof_get_buffer; - struct domain *d = current->domain; - int ret; - - if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) ) - return -EFAULT; - - /* - * We allocate xenoprof struct and buffers only at first time xenoprof_get_buffer - * is called. Memory is then kept until domain is destroyed. - */ - if ( (d->xenoprof == NULL) && - ((ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0)) < 0) ) - return ret; - - xenoprof_reset_buf(d); - - d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; - d->xenoprof->domain_ready = 0; - if ( primary_profiler == current->domain ) - d->xenoprof->is_primary = 1; - else - d->xenoprof->is_primary = 0; - - xenoprof_get_buffer.nbuf = d->xenoprof->nbuf; - xenoprof_get_buffer.bufsize = d->xenoprof->bufsize; - xenoprof_get_buffer.buf_maddr = __pa(d->xenoprof->rawbuf); - - if ( copy_to_guest(arg, &xenoprof_get_buffer, 1) ) - return -EFAULT; - - return 0; -} - -#define NONPRIV_OP(op) ( (op == XENOPROF_init) \ - || (op == XENOPROF_enable_virq) \ - || (op == XENOPROF_disable_virq) \ - || (op == XENOPROF_get_buffer)) - -int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg) -{ - int ret = 0; - - if ( (op < 0) || (op>XENOPROF_last_op) ) - { - printk("xenoprof: invalid operation %d for domain %d\n", - op, current->domain->domain_id); - return -EINVAL; - } - - if ( !NONPRIV_OP(op) && (current->domain != primary_profiler) ) - { - printk("xenoprof: dom %d denied privileged operation %d\n", - current->domain->domain_id, op); - return -EPERM; - } - - spin_lock(&xenoprof_lock); - - switch ( op ) - { - case XENOPROF_init: - ret = xenoprof_op_init(arg); - break; - - case XENOPROF_get_buffer: - ret = xenoprof_op_get_buffer(arg); - break; - - case XENOPROF_reset_active_list: - { - reset_active_list(); - ret = 0; - break; - } - case XENOPROF_reset_passive_list: - { - reset_passive_list(); - ret = 0; - break; - } - case XENOPROF_set_active: - { - domid_t domid; - if ( xenoprof_state != XENOPROF_IDLE ) { - ret = -EPERM; - break; - } - if ( copy_from_guest(&domid, arg, 1) ) { - ret = -EFAULT; - break; - } - ret = add_active_list(domid); - break; - } - case XENOPROF_set_passive: - { - if ( xenoprof_state != XENOPROF_IDLE ) { - ret = -EPERM; - break; - } - ret = add_passive_list(arg); - break; - } - case XENOPROF_reserve_counters: - if ( xenoprof_state != XENOPROF_IDLE ) { - ret = -EPERM; - break; - } - ret = nmi_reserve_counters(); - if ( !ret ) - xenoprof_state = XENOPROF_COUNTERS_RESERVED; - break; - - case XENOPROF_counter: - { - struct xenoprof_counter counter; - if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED || adomains == 0) { - ret = -EPERM; - break; - } - - if ( copy_from_guest(&counter, arg, 1) ) { - ret = -EFAULT; - break; - } - - if ( counter.ind > OP_MAX_COUNTER ) { - ret = -E2BIG; - break; - } - - counter_config[counter.ind].count = (unsigned long) counter.count; - counter_config[counter.ind].enabled = (unsigned long) counter.enabled; - counter_config[counter.ind].event = (unsigned long) counter.event; - counter_config[counter.ind].kernel = (unsigned long) counter.kernel; - counter_config[counter.ind].user = (unsigned long) counter.user; - counter_config[counter.ind].unit_mask = (unsigned long) counter.unit_mask; - - ret = 0; - break; - } - - case XENOPROF_setup_events: - if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED ) { - ret = -EPERM; - break; - } - ret = nmi_setup_events(); - if ( !ret ) - xenoprof_state = XENOPROF_READY; - break; - - case XENOPROF_enable_virq: - { - int i; - if ( current->domain == primary_profiler ) - { - nmi_enable_virq(); - xenoprof_reset_stat(); - for ( i = 0; i < pdomains; i++ ) { - xenoprof_reset_buf(passive_domains[i]); - } - } - xenoprof_reset_buf(current->domain); - ret = set_active(current->domain); - break; - } - - case XENOPROF_start: - ret = -EPERM; - if ( (xenoprof_state == XENOPROF_READY) && - (activated == adomains) ) - ret = nmi_start(); - - if ( ret == 0 ) - xenoprof_state = XENOPROF_PROFILING; - break; - - case XENOPROF_stop: - if ( xenoprof_state != XENOPROF_PROFILING ) { - ret = -EPERM; - break; - } - nmi_stop(); - xenoprof_state = XENOPROF_READY; - break; - - case XENOPROF_disable_virq: - if ( (xenoprof_state == XENOPROF_PROFILING) && - (is_active(current->domain)) ) { - ret = -EPERM; - break; - } - ret = reset_active(current->domain); - break; - - case XENOPROF_release_counters: - ret = -EPERM; - if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) || - (xenoprof_state == XENOPROF_READY) ) - { - xenoprof_state = XENOPROF_IDLE; - nmi_release_counters(); - nmi_disable_virq(); - reset_passive_list(); - ret = 0; - } - break; - - case XENOPROF_shutdown: - ret = -EPERM; - if ( xenoprof_state == XENOPROF_IDLE ) - { - activated = 0; - adomains=0; - primary_profiler = NULL; - ret = 0; - } - break; - - default: - ret = -EINVAL; - } - - spin_unlock(&xenoprof_lock); - - if ( ret < 0 ) - printk("xenoprof: operation %d failed for dom %d (status : %d)\n", - op, current->domain->domain_id, ret); - - return ret; } int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs) diff -r 9040d793dedf -r d1ab7aa09207 xen/common/Makefile --- a/xen/common/Makefile Fri Oct 20 21:21:34 2006 +0900 +++ b/xen/common/Makefile Thu Oct 26 14:26:36 2006 +0900 @@ -29,6 +29,7 @@ obj-y += xmalloc.o obj-$(perfc) += perfc.o obj-$(crash_debug) += gdbstub.o +obj-$(xenoprof) += xenoprof.o # Object file contains changeset and compiler information. version.o: $(BASEDIR)/include/xen/compile.h diff -r 9040d793dedf -r d1ab7aa09207 xen/include/public/xenoprof.h --- a/xen/include/public/xenoprof.h Fri Oct 20 21:21:34 2006 +0900 +++ b/xen/include/public/xenoprof.h Thu Oct 26 14:26:36 2006 +0900 @@ -69,7 +69,7 @@ struct xenoprof_get_buffer { int32_t max_samples; int32_t nbuf; int32_t bufsize; - uint64_t buf_maddr; + uint64_t buf_gmaddr; }; typedef struct xenoprof_get_buffer xenoprof_get_buffer_t; DEFINE_XEN_GUEST_HANDLE(xenoprof_get_buffer_t); @@ -92,7 +92,7 @@ typedef struct xenoprof_passive { int32_t max_samples; int32_t nbuf; int32_t bufsize; - uint64_t buf_maddr; + uint64_t buf_gmaddr; } xenoprof_passive_t; DEFINE_XEN_GUEST_HANDLE(xenoprof_passive_t); diff -r 9040d793dedf -r d1ab7aa09207 xen/include/xen/xenoprof.h --- a/xen/include/xen/xenoprof.h Fri Oct 20 21:21:34 2006 +0900 +++ b/xen/include/xen/xenoprof.h Thu Oct 26 14:26:36 2006 +0900 @@ -11,6 +11,7 @@ #define __XEN_XENOPROF_H__ #include +#include #define XENOPROF_DOMAIN_IGNORED 0 #define XENOPROF_DOMAIN_ACTIVE 1 @@ -40,4 +41,8 @@ struct domain; struct domain; void free_xenoprof_pages(struct domain *d); +int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg); + +extern struct domain *xenoprof_primary_profiler; + #endif /* __XEN__XENOPROF_H__ */ diff -r 9040d793dedf -r d1ab7aa09207 xen/common/xenoprof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/common/xenoprof.c Thu Oct 26 14:26:36 2006 +0900 @@ -0,0 +1,759 @@ +/* + * Copyright (C) 2005 Hewlett-Packard Co. + * written by Aravind Menon & Jose Renato Santos + * (email: xenoprof@xxxxxxxxxxxxx) + * + * Copyright (c) 2006 Isaku Yamahata + * VA Linux Systems Japan K.K. + * arch generic xenoprof and IA64 support. + */ + +#include +#include +#include +#include + +#define XENOPROF_DEBUG +//#undef XENOPROF_DEBUG +#ifdef XENOPROF_DEBUG +#define XENOPROF_PRINTD(fmt, ...) \ + printk("%s:%d " fmt, __func__, __LINE__, ##__VA_ARGS__) +#else +#define XENOPROF_PRINTD(fmt, ...) do { } while (0) +#endif + +/* Limit amount of pages used for shared buffer (per domain) */ +#define MAX_OPROF_SHARED_PAGES 32 + +/* Lock protecting the following global state */ +static DEFINE_SPINLOCK(xenoprof_lock); + +struct domain *active_domains[MAX_OPROF_DOMAINS]; +int active_ready[MAX_OPROF_DOMAINS]; +unsigned int adomains; + +struct domain *passive_domains[MAX_OPROF_DOMAINS]; +unsigned int pdomains; + +unsigned int activated; +struct domain *xenoprof_primary_profiler; +int xenoprof_state = XENOPROF_IDLE; + +u64 total_samples; +u64 invalid_buffer_samples; +u64 corrupted_buffer_samples; +u64 lost_samples; +u64 active_samples; +u64 passive_samples; +u64 idle_samples; +u64 others_samples; + +int is_active(struct domain *d) +{ + struct xenoprof *x = d->xenoprof; + return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_ACTIVE)); +} + +int is_passive(struct domain *d) +{ + struct xenoprof *x = d->xenoprof; + return ((x != NULL) && (x->domain_type == XENOPROF_DOMAIN_PASSIVE)); +} + +int is_profiled(struct domain *d) +{ + return (is_active(d) || is_passive(d)); +} + +static void xenoprof_reset_stat(void) +{ + total_samples = 0; + invalid_buffer_samples = 0; + corrupted_buffer_samples = 0; + lost_samples = 0; + active_samples = 0; + passive_samples = 0; + idle_samples = 0; + others_samples = 0; +} + +static void xenoprof_reset_buf(struct domain *d) +{ + int j; + struct xenoprof_buf *buf; + + if ( d->xenoprof == NULL ) + { + printk("xenoprof_reset_buf: ERROR - Unexpected " + "Xenoprof NULL pointer \n"); + return; + } + + for ( j = 0; j < MAX_VIRT_CPUS; j++ ) + { + buf = d->xenoprof->vcpu[j].buffer; + if ( buf != NULL ) + { + buf->event_head = 0; + buf->event_tail = 0; + } + } +} + +static int +share_xenoprof_page_with_guest(struct domain* d, unsigned long mfn, int npages) +{ + int i; + + /* Share pages so that kernel can map it */ + for (i = 0; i < npages; i++) { + struct page_info* page = mfn_to_page(mfn + i); + if ((page->count_info & (PGC_allocated|PGC_count_mask)) != 0) { + DPRINTK("%s: mfn 0x%lx page->count_info 0x%x\n", + __func__, mfn + i, page->count_info); + return -EBUSY; + } + page->count_info = 0; + page_set_owner(page, NULL); + } + + for (i = 0; i < npages; i++) + share_xen_page_with_guest(mfn_to_page(mfn + i), d, XENSHARE_writable); + return 0; +} + +static void +unshare_xenoprof_page_with_guest(unsigned long mfn, int npages) +{ + int i; + + for (i = 0; i < npages; i++) { + struct page_info* page = mfn_to_page(mfn + i); + BUG_ON(page_get_owner(page) != current->domain); + if (test_and_clear_bit(_PGC_allocated, &page->count_info)) + put_page(page); + } +} + +static void +xenoprof_shared_gmfn_with_guest(struct domain* d, + unsigned long maddr, unsigned long gmaddr, + int npages) +{ + int i; + + for (i = 0; i < npages; i++, maddr += PAGE_SIZE, gmaddr += PAGE_SIZE) { + BUG_ON(page_get_owner(maddr_to_page(maddr)) != d); + xenoprof_shared_gmfn(d, gmaddr, maddr); + } +} + +static char *alloc_xenoprof_buf(struct domain *d, int npages, uint64_t gmaddr) +{ + char *rawbuf; + int order; + + /* allocate pages to store sample buffer shared with domain */ + order = get_order_from_pages(npages); + rawbuf = alloc_xenheap_pages(order); + if ( rawbuf == NULL ) + { + printk("alloc_xenoprof_buf(): memory allocation failed\n"); + return 0; + } + + return rawbuf; +} + +static int alloc_xenoprof_struct( + struct domain *d, int max_samples, int is_passive, uint64_t gmaddr) +{ + struct vcpu *v; + int nvcpu, npages, bufsize, max_bufsize; + unsigned max_max_samples; + int i; + + d->xenoprof = xmalloc(struct xenoprof); + + if ( d->xenoprof == NULL ) + { + printk ("alloc_xenoprof_struct(): memory " + "allocation (xmalloc) failed\n"); + return -ENOMEM; + } + + memset(d->xenoprof, 0, sizeof(*d->xenoprof)); + + nvcpu = 0; + for_each_vcpu ( d, v ) + nvcpu++; + + /* reduce max_samples if necessary to limit pages allocated */ + max_bufsize = (MAX_OPROF_SHARED_PAGES * PAGE_SIZE) / nvcpu; + max_max_samples = ( (max_bufsize - sizeof(struct xenoprof_buf)) / + sizeof(struct event_log) ) + 1; + if ( (unsigned)max_samples > max_max_samples ) + max_samples = max_max_samples; + + bufsize = sizeof(struct xenoprof_buf) + + (max_samples - 1) * sizeof(struct event_log); + npages = (nvcpu * bufsize - 1) / PAGE_SIZE + 1; + + d->xenoprof->rawbuf = alloc_xenoprof_buf(is_passive ? dom0 : d, npages, + gmaddr); + + if ( d->xenoprof->rawbuf == NULL ) + { + xfree(d->xenoprof); + d->xenoprof = NULL; + return -ENOMEM; + } + + d->xenoprof->npages = npages; + d->xenoprof->nbuf = nvcpu; + d->xenoprof->bufsize = bufsize; + d->xenoprof->domain_ready = 0; + d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; + + /* Update buffer pointers for active vcpus */ + i = 0; + for_each_vcpu ( d, v ) + { + d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples; + d->xenoprof->vcpu[v->vcpu_id].buffer = + (struct xenoprof_buf *)&d->xenoprof->rawbuf[i * bufsize]; + d->xenoprof->vcpu[v->vcpu_id].buffer->event_size = max_samples; + d->xenoprof->vcpu[v->vcpu_id].buffer->vcpu_id = v->vcpu_id; + + i++; + /* in the unlikely case that the number of active vcpus changes */ + if ( i >= nvcpu ) + break; + } + + return 0; +} + +void free_xenoprof_pages(struct domain *d) +{ + struct xenoprof *x; + int order; + + x = d->xenoprof; + if ( x == NULL ) + return; + + if ( x->rawbuf != NULL ) + { + order = get_order_from_pages(x->npages); + free_xenheap_pages(x->rawbuf, order); + } + + xfree(x); + d->xenoprof = NULL; +} + +static int active_index(struct domain *d) +{ + int i; + + for ( i = 0; i < adomains; i++ ) + if ( active_domains[i] == d ) + return i; + + return -1; +} + +static int set_active(struct domain *d) +{ + int ind; + struct xenoprof *x; + + ind = active_index(d); + if ( ind < 0 ) + return -EPERM; + + x = d->xenoprof; + if ( x == NULL ) + return -EPERM; + + x->domain_ready = 1; + x->domain_type = XENOPROF_DOMAIN_ACTIVE; + active_ready[ind] = 1; + activated++; + + return 0; +} + +static int reset_active(struct domain *d) +{ + int ind; + struct xenoprof *x; + + ind = active_index(d); + if ( ind < 0 ) + return -EPERM; + + x = d->xenoprof; + if ( x == NULL ) + return -EPERM; + + x->domain_ready = 0; + x->domain_type = XENOPROF_DOMAIN_IGNORED; + active_ready[ind] = 0; + active_domains[ind] = NULL; + activated--; + put_domain(d); + + if ( activated <= 0 ) + adomains = 0; + + return 0; +} + +static void reset_passive(struct domain *d) +{ + struct xenoprof *x; + + if (d==0) + return; + + x = d->xenoprof; + if ( x == NULL ) + return; + + unshare_xenoprof_page_with_guest(virt_to_mfn(x->rawbuf), x->npages); + x->domain_type = XENOPROF_DOMAIN_IGNORED; + + return; +} + +static void reset_active_list(void) +{ + int i; + + for ( i = 0; i < adomains; i++ ) + { + if ( active_ready[i] ) + { + reset_active(active_domains[i]); + } + } + + adomains = 0; + activated = 0; +} + +static void reset_passive_list(void) +{ + int i; + + for ( i = 0; i < pdomains; i++ ) + { + reset_passive(passive_domains[i]); + put_domain(passive_domains[i]); + passive_domains[i] = NULL; + } + + pdomains = 0; +} + +static int add_active_list(domid_t domid) +{ + struct domain *d; + + if ( adomains >= MAX_OPROF_DOMAINS ) + return -E2BIG; + + d = find_domain_by_id(domid); + if ( d == NULL ) + return -EINVAL; + + active_domains[adomains] = d; + active_ready[adomains] = 0; + adomains++; + + return 0; +} + +static int add_passive_list(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_passive passive; + struct domain *d; + int ret = 0; + + if ( pdomains >= MAX_OPROF_DOMAINS ) + return -E2BIG; + + if ( copy_from_guest(&passive, arg, 1) ) + return -EFAULT; + + d = find_domain_by_id(passive.domain_id); + if ( d == NULL ) + return -EINVAL; + + if ( (d->xenoprof == NULL) && + ((ret = alloc_xenoprof_struct(d, passive.max_samples, 1, + passive.buf_gmaddr)) < 0) ) { + put_domain(d); + return -ENOMEM; + } + + ret = share_xenoprof_page_with_guest(current->domain, + virt_to_mfn(d->xenoprof->rawbuf), d->xenoprof->npages); + if (ret) { + put_domain(d); + return ret; + } + + d->xenoprof->domain_type = XENOPROF_DOMAIN_PASSIVE; + passive.nbuf = d->xenoprof->nbuf; + passive.bufsize = d->xenoprof->bufsize; + if (!shadow_mode_translate(d)) + passive.buf_gmaddr = __pa(d->xenoprof->rawbuf); + else + xenoprof_shared_gmfn_with_guest(current->domain, __pa(d->xenoprof->rawbuf), passive.buf_gmaddr, d->xenoprof->npages); + + if ( copy_to_guest(arg, &passive, 1) ) { + put_domain(d); + return -EFAULT; + } + + passive_domains[pdomains] = d; + pdomains++; + + return ret; +} + +void xenoprof_log_event( + struct vcpu *vcpu, unsigned long eip, int mode, int event) +{ + struct xenoprof_vcpu *v; + struct xenoprof_buf *buf; + int head; + int tail; + int size; + + + total_samples++; + + /* ignore samples of un-monitored domains */ + /* Count samples in idle separate from other unmonitored domains */ + if ( !is_profiled(vcpu->domain) ) + { + others_samples++; + return; + } + + v = &vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id]; + + /* Sanity check. Should never happen */ + if ( v->buffer == NULL ) + { + invalid_buffer_samples++; + return; + } + + buf = vcpu->domain->xenoprof->vcpu[vcpu->vcpu_id].buffer; + + head = buf->event_head; + tail = buf->event_tail; + size = v->event_size; + + /* make sure indexes in shared buffer are sane */ + if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) ) + { + corrupted_buffer_samples++; + return; + } + + if ( (head == tail - 1) || (head == size - 1 && tail == 0) ) + { + buf->lost_samples++; + lost_samples++; + } + else + { + buf->event_log[head].eip = eip; + buf->event_log[head].mode = mode; + buf->event_log[head].event = event; + head++; + if ( head >= size ) + head = 0; + buf->event_head = head; + if ( is_active(vcpu->domain) ) + active_samples++; + else + passive_samples++; + if ( mode == 0 ) + buf->user_samples++; + else if ( mode == 1 ) + buf->kernel_samples++; + else + buf->xen_samples++; + } +} + +static int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_init xenoprof_init; + int ret; + + if ( copy_from_guest(&xenoprof_init, arg, 1) ) + return -EFAULT; + + if ( (ret = xenoprof_arch_init(&xenoprof_init.num_events, + &xenoprof_init.is_primary, + xenoprof_init.cpu_type)) ) + return ret; + + if ( copy_to_guest(arg, &xenoprof_init, 1) ) + return -EFAULT; + + if ( xenoprof_init.is_primary ) + xenoprof_primary_profiler = current->domain; + + return 0; +} + +static int xenoprof_op_get_buffer(XEN_GUEST_HANDLE(void) arg) +{ + struct xenoprof_get_buffer xenoprof_get_buffer; + struct domain *d = current->domain; + int ret; + + if ( copy_from_guest(&xenoprof_get_buffer, arg, 1) ) + return -EFAULT; + + /* + * We allocate xenoprof struct and buffers only at first time xenoprof_get_buffer + * is called. Memory is then kept until domain is destroyed. + */ + if ( (d->xenoprof == NULL) && + ((ret = alloc_xenoprof_struct(d, xenoprof_get_buffer.max_samples, 0, + xenoprof_get_buffer.buf_gmaddr)) < 0) ) + return ret; + + ret = share_xenoprof_page_with_guest(d, virt_to_mfn(d->xenoprof->rawbuf), + d->xenoprof->npages); + if (ret) + return ret; + + xenoprof_reset_buf(d); + + d->xenoprof->domain_type = XENOPROF_DOMAIN_IGNORED; + d->xenoprof->domain_ready = 0; + if ( xenoprof_primary_profiler == current->domain ) + d->xenoprof->is_primary = 1; + else + d->xenoprof->is_primary = 0; + + xenoprof_get_buffer.nbuf = d->xenoprof->nbuf; + xenoprof_get_buffer.bufsize = d->xenoprof->bufsize; + if (!shadow_mode_translate(d)) + xenoprof_get_buffer.buf_gmaddr = __pa(d->xenoprof->rawbuf); + else + xenoprof_shared_gmfn_with_guest(d, __pa(d->xenoprof->rawbuf), + xenoprof_get_buffer.buf_gmaddr, + d->xenoprof->npages); + + if ( copy_to_guest(arg, &xenoprof_get_buffer, 1) ) + return -EFAULT; + + return 0; +} + +#define NONPRIV_OP(op) ( (op == XENOPROF_init) \ + || (op == XENOPROF_enable_virq) \ + || (op == XENOPROF_disable_virq) \ + || (op == XENOPROF_get_buffer)) + +int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg) +{ + int ret = 0; + + if ( (op < 0) || (op>XENOPROF_last_op) ) + { + printk("xenoprof: invalid operation %d for domain %d\n", + op, current->domain->domain_id); + return -EINVAL; + } + + if ( !NONPRIV_OP(op) && (current->domain != xenoprof_primary_profiler) ) + { + printk("xenoprof: dom %d denied privileged operation %d\n", + current->domain->domain_id, op); + return -EPERM; + } + + spin_lock(&xenoprof_lock); + + switch ( op ) + { + case XENOPROF_init: + ret = xenoprof_op_init(arg); + break; + + case XENOPROF_get_buffer: + ret = xenoprof_op_get_buffer(arg); + break; + + case XENOPROF_reset_active_list: + { + reset_active_list(); + ret = 0; + break; + } + case XENOPROF_reset_passive_list: + { + reset_passive_list(); + ret = 0; + break; + } + case XENOPROF_set_active: + { + domid_t domid; + if ( xenoprof_state != XENOPROF_IDLE ) { + ret = -EPERM; + break; + } + if ( copy_from_guest(&domid, arg, 1) ) { + ret = -EFAULT; + break; + } + ret = add_active_list(domid); + break; + } + case XENOPROF_set_passive: + { + if ( xenoprof_state != XENOPROF_IDLE ) { + ret = -EPERM; + break; + } + ret = add_passive_list(arg); + break; + } + case XENOPROF_reserve_counters: + if ( xenoprof_state != XENOPROF_IDLE ) { + ret = -EPERM; + break; + } + ret = xenoprof_arch_reserve_counters(); + if ( !ret ) + xenoprof_state = XENOPROF_COUNTERS_RESERVED; + break; + + case XENOPROF_counter: + if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED || adomains == 0) { + ret = -EPERM; + break; + } + + ret = xenoprof_arch_counter(arg); + break; + + case XENOPROF_setup_events: + if ( xenoprof_state != XENOPROF_COUNTERS_RESERVED ) { + ret = -EPERM; + break; + } + ret = xenoprof_arch_setup_events(); + if ( !ret ) + xenoprof_state = XENOPROF_READY; + break; + + case XENOPROF_enable_virq: + { + int i; + if ( current->domain == xenoprof_primary_profiler ) + { + xenoprof_arch_enable_virq(); + xenoprof_reset_stat(); + for ( i = 0; i < pdomains; i++ ) { + xenoprof_reset_buf(passive_domains[i]); + } + } + xenoprof_reset_buf(current->domain); + ret = set_active(current->domain); + break; + } + + case XENOPROF_start: + ret = -EPERM; + if ( (xenoprof_state == XENOPROF_READY) && + (activated == adomains) ) + ret = xenoprof_arch_start(); + if ( ret == 0 ) + xenoprof_state = XENOPROF_PROFILING; + break; + + case XENOPROF_stop: + if ( xenoprof_state != XENOPROF_PROFILING ) { + ret = -EPERM; + break; + } + xenoprof_arch_stop(); + xenoprof_state = XENOPROF_READY; + break; + + case XENOPROF_disable_virq: + { + struct xenoprof *x = current->domain->xenoprof; + if ( (xenoprof_state == XENOPROF_PROFILING) && + (is_active(current->domain)) ) { + ret = -EPERM; + break; + } + ret = reset_active(current->domain); + if (ret) + break; + x = current->domain->xenoprof; /*reset_active() guarantees x != NULL*/ + unshare_xenoprof_page_with_guest(virt_to_mfn(x->rawbuf), x->npages); + break; + } + case XENOPROF_release_counters: + ret = -EPERM; + if ( (xenoprof_state == XENOPROF_COUNTERS_RESERVED) || + (xenoprof_state == XENOPROF_READY) ) + { + xenoprof_state = XENOPROF_IDLE; + xenoprof_arch_release_counters(); + xenoprof_arch_disable_virq(); + reset_passive_list(); + ret = 0; + } + break; + + case XENOPROF_shutdown: + ret = -EPERM; + if ( xenoprof_state == XENOPROF_IDLE ) + { + activated = 0; + adomains=0; + xenoprof_primary_profiler = NULL; + ret = 0; + } + break; + + default: + ret = -EINVAL; + } + + spin_unlock(&xenoprof_lock); + + if ( ret < 0 ) + printk("xenoprof: operation %d failed for dom %d (status : %d)\n", + op, current->domain->domain_id, ret); + + return ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -r 9040d793dedf -r d1ab7aa09207 xen/include/asm-x86/xenoprof.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/xenoprof.h Thu Oct 26 14:26:36 2006 +0900 @@ -0,0 +1,67 @@ +/****************************************************************************** + * asm-x86/xenoprof.h + * xenoprof x86 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 nmi_init(int *num_events, int *is_primary, char *cpu_type); +int nmi_reserve_counters(void); +int nmi_setup_events(void); +int nmi_enable_virq(void); +int nmi_start(void); +void nmi_stop(void); +void nmi_disable_virq(void); +void nmi_release_counters(void); + +#define xenoprof_arch_init(num_events, is_primary, cpu_type) \ + nmi_init(num_events, is_primary, cpu_type) +#define xenoprof_arch_reserve_counters() nmi_reserve_counters() +#define xenoprof_arch_setup_events() nmi_setup_events() +#define xenoprof_arch_enable_virq() nmi_enable_virq() +#define xenoprof_arch_start() nmi_start() +#define xenoprof_arch_stop() nmi_stop() +#define xenoprof_arch_disable_virq() nmi_disable_virq() +#define xenoprof_arch_release_counters() nmi_release_counters() + +int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg); + +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) \ + do { \ + (void)(maddr); \ + BUG(); /* not supported yet */ \ + } while (0) + +#endif /* __ASM_XENOPROF_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */