# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Date 1161840458 -32400 # Node ID bd4247feec262649a546e62fe98cd89540ce42f0 # Parent db608db1c300c00e7fb309e10f16b90add78b798 xenoprof ia64 xen side PATCHNAME: xenoprof_ia64_xen_side Signed-off-by: Isaku Yamahata diff -r db608db1c300 -r bd4247feec26 xen/arch/ia64/Rules.mk --- a/xen/arch/ia64/Rules.mk Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/Rules.mk Thu Oct 26 14:27:38 2006 +0900 @@ -3,6 +3,7 @@ HAS_ACPI := y HAS_VGA := y +xenoprof := y VALIDATE_VT ?= n no_warns ?= n xen_ia64_expose_p2m ?= y diff -r db608db1c300 -r bd4247feec26 xen/arch/ia64/linux-xen/Makefile --- a/xen/arch/ia64/linux-xen/Makefile Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/linux-xen/Makefile Thu Oct 26 14:27:38 2006 +0900 @@ -18,3 +18,5 @@ obj-y += iosapic.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 -r db608db1c300 -r bd4247feec26 xen/arch/ia64/linux-xen/perfmon.c --- a/xen/arch/ia64/linux-xen/perfmon.c Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/linux-xen/perfmon.c Thu Oct 26 14:27:38 2006 +0900 @@ -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 @@ -28,29 +34,52 @@ #include #include #include +#ifndef XEN #include +#endif #include +#ifndef XEN #include +#endif #include #include +#ifndef XEN #include #include #include #include +#endif #include +#ifndef XEN #include #include #include - +#endif + +#ifndef XEN #include +#else +#include +#endif #include #include #include #include +#ifndef XEN #include +#endif #include #include #include + +#ifdef XEN +#include +#include +#define CONFIG_PERFMON 1 +#define pid vcpu_id +#define thread arch._thread +#define task_pt_regs vcpu_regs +#endif #ifdef CONFIG_PERFMON /* @@ -114,7 +143,9 @@ #define CTX_OVFL_NOBLOCK(c) ((c)->ctx_fl_block == 0) #define CTX_HAS_SMPL(c) ((c)->ctx_fl_is_sampling) +#ifndef XEN #define PFM_CTX_TASK(h) (h)->ctx_task +#endif #define PMU_PMC_OI 5 /* position of pmc.oi bit */ @@ -283,11 +314,15 @@ typedef struct pfm_context { pfm_context_flags_t ctx_flags; /* bitmask of flags (block reason incl.) */ unsigned int ctx_state; /* state: active/inactive (no bitfield) */ +#ifndef XEN struct task_struct *ctx_task; /* task to which context is attached */ +#endif 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 +355,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 +363,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 +408,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 +539,14 @@ static pfm_stats_t pfm_stats[NR_CPUS]; 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 +558,7 @@ pfm_sysctl_t pfm_sysctl; 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 +578,12 @@ static struct ctl_table_header *pfm_sysc 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 +615,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 +630,7 @@ pfm_unprotect_ctx_ctxsw(pfm_context_t *x 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 +655,19 @@ static struct file_system_type pfm_fs_ty .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 +693,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 +804,7 @@ pfm_write_soft_counter(pfm_context_t *ct ia64_set_pmd(i, val & ovfl_val); } +#ifndef XEN static pfm_msg_t * pfm_get_new_msg(pfm_context_t *ctx) { @@ -837,6 +892,7 @@ pfm_rvfree(void *mem, unsigned long size } return; } +#endif static pfm_context_t * pfm_context_alloc(void) @@ -864,6 +920,7 @@ pfm_context_free(pfm_context_t *ctx) } } +#ifndef XEN static void pfm_mask_monitoring(struct task_struct *task) { @@ -1034,6 +1091,7 @@ pfm_restore_monitoring(struct task_struc } pfm_set_psr_l(psr); } +#endif static inline void pfm_save_pmds(unsigned long *pmds, unsigned long mask) @@ -1047,6 +1105,7 @@ pfm_save_pmds(unsigned long *pmds, unsig } } +#ifndef XEN /* * reload from thread state (used for ctxw only) */ @@ -1100,7 +1159,37 @@ pfm_copy_pmds(struct task_struct *task, 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 +1222,23 @@ pfm_restore_pmcs(unsigned long *pmcs, un } 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 +1411,11 @@ pfm_reserve_session(struct task_struct * 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 +1442,11 @@ pfm_reserve_session(struct task_struct * 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 +1506,7 @@ pfm_unreserve_session(pfm_context_t *ctx return 0; } +#ifndef XEN /* * removes virtual mapping of the sampling buffer. * IMPORTANT: cannot be called with interrupts disable, e.g. inside @@ -1428,6 +1543,7 @@ pfm_remove_smpl_mapping(struct task_stru return 0; } +#endif /* * free actual physical storage used by sampling buffer @@ -1477,6 +1593,7 @@ pfm_exit_smpl_buffer(pfm_buffer_fmt_t *f } +#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 +2018,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 +2034,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 +2069,14 @@ pfm_close(struct inode *inode, struct fi } 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 +2175,15 @@ pfm_close(struct inode *inode, struct fi 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 +2224,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 +2245,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 +2257,7 @@ doit: return 0; } +#ifndef XEN static int pfm_no_open(struct inode *irrelevant, struct file *dontcare) { @@ -2255,6 +2397,7 @@ pfm_remap_buffer(struct vm_area_struct * } return 0; } +#endif /* * allocate a sampling buffer and remaps it into the user address space of the task @@ -2262,6 +2405,7 @@ static int 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 +2518,13 @@ error_kmem: pfm_rvfree(smpl_buf, size); return -ENOMEM; -} - +#else + //XXX + return 0; +#endif +} + +#ifndef XEN /* * XXX: do something better here */ @@ -2399,6 +2548,7 @@ pfm_bad_permissions(struct task_struct * || (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 +2685,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 +2793,31 @@ pfm_get_task(pfm_context_t *ctx, pid_t p } 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 +2826,7 @@ pfm_context_create(pfm_context_t *ctx, v ctx = pfm_context_alloc(); if (!ctx) goto error; +#ifndef XEN ret = pfm_alloc_fd(&filp); if (ret < 0) goto error_file; @@ -2673,6 +2836,7 @@ pfm_context_create(pfm_context_t *ctx, v * attach context to file */ filp->private_data = ctx; +#endif /* * does the user want to sample? @@ -2704,10 +2868,12 @@ pfm_context_create(pfm_context_t *ctx, v * 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 +2881,14 @@ pfm_context_create(pfm_context_t *ctx, v 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 +2904,35 @@ pfm_context_create(pfm_context_t *ctx, v */ 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 @@ -2857,12 +3041,19 @@ pfm_reset_regs(pfm_context_t *ctx, unsig ia64_srlz_d(); } +#ifndef XEN static int pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ +#else +static int +pfm_write_pmcs(pfm_context_t *ctx, pfarg_reg_t *req, int count) +#endif +{ +#ifndef XEN struct thread_struct *thread = NULL; struct task_struct *task; pfarg_reg_t *req = (pfarg_reg_t *)arg; +#endif unsigned long value, pmc_pm; unsigned long smpl_pmds, reset_pmds, impl_pmds; unsigned int cnum, reg_flags, flags, pmc_type; @@ -2875,11 +3066,14 @@ pfm_write_pmcs(pfm_context_t *ctx, void state = ctx->ctx_state; is_loaded = state == PFM_CTX_LOADED ? 1 : 0; is_system = ctx->ctx_fl_system; +#ifndef XEN task = ctx->ctx_task; +#endif impl_pmds = pmu_conf->impl_pmds[0]; if (state == PFM_CTX_ZOMBIE) return -EINVAL; +#ifndef XEN if (is_loaded) { thread = &task->thread; /* @@ -2893,6 +3087,13 @@ pfm_write_pmcs(pfm_context_t *ctx, void } 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++) { @@ -2974,7 +3175,12 @@ pfm_write_pmcs(pfm_context_t *ctx, void * execute write checker, if any */ if (likely(expert_mode == 0 && wr_func)) { +#ifndef XEN ret = (*wr_func)(task, ctx, cnum, &value, regs); +#else + //XXX task = NULL + ret = (*wr_func)(NULL, ctx, cnum, &value, NULL); +#endif if (ret) goto error; ret = -EINVAL; } @@ -3046,6 +3252,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void */ ctx->ctx_pmcs[cnum] = value; +#ifndef XEN if (is_loaded) { /* * write thread state @@ -3071,6 +3278,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void } #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, @@ -3099,11 +3307,18 @@ error: return ret; } +#ifndef XEN static int pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ +#else +static int +pfm_write_pmds(pfm_context_t *ctx, void *arg, int count) +#endif +{ +#ifndef XEN struct thread_struct *thread = NULL; struct task_struct *task; +#endif pfarg_reg_t *req = (pfarg_reg_t *)arg; unsigned long value, hw_value, ovfl_mask; unsigned int cnum; @@ -3117,10 +3332,13 @@ pfm_write_pmds(pfm_context_t *ctx, void is_loaded = state == PFM_CTX_LOADED ? 1 : 0; is_system = ctx->ctx_fl_system; ovfl_mask = pmu_conf->ovfl_val; +#ifndef XEN task = ctx->ctx_task; +#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 +3356,12 @@ pfm_write_pmds(pfm_context_t *ctx, void } 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++) { @@ -3158,7 +3382,12 @@ pfm_write_pmds(pfm_context_t *ctx, void if (unlikely(expert_mode == 0 && wr_func)) { unsigned long v = value; +#ifndef XEN ret = (*wr_func)(task, ctx, cnum, &v, regs); +#else + //XXX task = NULL, regs == NULL + ret = (*wr_func)(NULL, ctx, cnum, &v, NULL); +#endif if (ret) goto abort_mission; value = v; @@ -3230,6 +3459,8 @@ pfm_write_pmds(pfm_context_t *ctx, void ctx->ctx_ovfl_regs[0] &= ~1UL << cnum; } + //XXX FIXME +#ifndef XEN if (is_loaded) { /* * write thread state @@ -3252,6 +3483,7 @@ pfm_write_pmds(pfm_context_t *ctx, void #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 +3520,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 +3704,7 @@ pfm_mod_read_pmds(struct task_struct *ta 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 +3786,7 @@ pfm_release_debug_registers(struct task_ return ret; } +#ifndef XEN static int pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { @@ -3720,6 +3955,7 @@ pfm_debug(pfm_context_t *ctx, void *arg, } return 0; } +#endif /* * arg can be NULL and count can be zero for this function @@ -3727,8 +3963,12 @@ static int 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; struct task_struct *task; +#else + struct thread_struct *th = NULL; +#endif pfarg_dbreg_t *req = (pfarg_dbreg_t *)arg; unsigned long flags; dbreg_t dbreg; @@ -3743,16 +3983,27 @@ pfm_write_ibr_dbr(int mode, pfm_context_ state = ctx->ctx_state; is_loaded = state == PFM_CTX_LOADED ? 1 : 0; is_system = ctx->ctx_fl_system; +#ifndef XEN task = ctx->ctx_task; +#else + BUG_ON(regs != NULL); + // currently dbrs, ibrs aren't supported + BUG(); +#endif if (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. */ if (is_loaded) { +#ifndef XEN thread = &task->thread; +#else + th = &task->thread; +#endif /* * 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. @@ -3764,6 +4015,11 @@ pfm_write_ibr_dbr(int mode, pfm_context_ } can_access_pmu = GET_PMU_OWNER() == task || is_system ? 1 : 0; } +#else + //XXX + if (is_loaded) + return -EBUSY; +#endif /* * we do not need to check for ipsr.db because we do clear ibr.x, dbr.r, and dbr.w @@ -3777,8 +4033,14 @@ pfm_write_ibr_dbr(int mode, pfm_context_ /* * don't bother if we are loaded and task is being debugged */ +#ifndef XEN if (is_loaded && (thread->flags & IA64_THREAD_DBG_VALID) != 0) { +#else + if (is_loaded && (th->flags & IA64_THREAD_DBG_VALID) != 0) { +#endif +#ifndef XEN DPRINT(("debug registers already in use for [%d]\n", task->pid)); +#endif return -EBUSY; } @@ -3819,7 +4081,9 @@ pfm_write_ibr_dbr(int mode, pfm_context_ * 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 +4247,7 @@ pfm_get_features(pfm_context_t *ctx, voi return 0; } +#ifndef XEN static int pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) { @@ -4201,10 +4466,17 @@ pfm_check_task_exist(pfm_context_t *ctx) return ret; } - +#endif + +#ifndef XEN static int pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ +#else +static int +pfm_context_load(pfm_context_t *ctx, void *arg) +#endif +{ +#ifndef XEN struct task_struct *task; struct thread_struct *thread; struct pfm_context_t *old; @@ -4212,8 +4484,11 @@ pfm_context_load(pfm_context_t *ctx, voi #ifndef CONFIG_SMP struct task_struct *owner_task = NULL; #endif +#endif pfarg_load_t *req = (pfarg_load_t *)arg; +#ifndef XEN unsigned long *pmcs_source, *pmds_source; +#endif int the_cpu; int ret = 0; int state, is_system, set_dbregs = 0; @@ -4230,6 +4505,7 @@ pfm_context_load(pfm_context_t *ctx, voi 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 +4531,16 @@ pfm_context_load(pfm_context_t *ctx, voi } 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 +4568,9 @@ pfm_context_load(pfm_context_t *ctx, voi if (ret) goto error; } +#else + BUG_ON(ctx->ctx_fl_using_dbreg); +#endif /* * SMP system-wide monitoring implies self-monitoring. @@ -4318,6 +4605,7 @@ pfm_context_load(pfm_context_t *ctx, voi * * XXX: needs to be atomic */ +#ifndef XEN DPRINT(("before cmpxchg() old_ctx=%p new_ctx=%p\n", thread->pfm_context, ctx)); @@ -4329,13 +4617,16 @@ pfm_context_load(pfm_context_t *ctx, voi } pfm_reset_msgq(ctx); +#endif ctx->ctx_state = PFM_CTX_LOADED; +#ifndef XEN /* * link context to task */ ctx->ctx_task = task; +#endif if (is_system) { /* @@ -4346,9 +4637,14 @@ pfm_context_load(pfm_context_t *ctx, voi 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 +4713,29 @@ pfm_context_load(pfm_context_t *ctx, voi 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 +4758,9 @@ error: } } } +#else + BUG_ON(set_dbregs); +#endif return ret; } @@ -4456,17 +4772,30 @@ error: * which also grabs the context lock and would therefore be blocked * until we are here. */ +#ifndef XEN static void pfm_flush_pmds(struct task_struct *, pfm_context_t *ctx); - +#else +static void pfm_flush_pmds(pfm_context_t *ctx); +#endif + +#ifndef XEN static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs) -{ +#else +static int +pfm_context_unload(pfm_context_t *ctx) +#endif +{ +#ifndef XEN struct task_struct *task = PFM_CTX_TASK(ctx); struct pt_regs *tregs; +#endif int prev_state, is_system; int ret; +#ifndef XEN DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1)); +#endif prev_state = ctx->ctx_state; is_system = ctx->ctx_fl_system; @@ -4482,8 +4811,13 @@ pfm_context_unload(pfm_context_t *ctx, v /* * 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; @@ -4502,11 +4836,15 @@ pfm_context_unload(pfm_context_t *ctx, v PFM_CPUINFO_CLEAR(PFM_CPUINFO_SYST_WIDE); PFM_CPUINFO_CLEAR(PFM_CPUINFO_EXCL_IDLE); +#ifndef XEN /* * save PMDs in context * release ownership */ pfm_flush_pmds(current, ctx); +#else + pfm_flush_pmds(ctx); +#endif /* * at this point we are done with the PMU @@ -4515,6 +4853,7 @@ pfm_context_unload(pfm_context_t *ctx, v if (prev_state != PFM_CTX_ZOMBIE) pfm_unreserve_session(ctx, 1 , ctx->ctx_cpu); +#ifndef XEN /* * disconnect context from task */ @@ -4523,6 +4862,7 @@ pfm_context_unload(pfm_context_t *ctx, v * disconnect task from context */ ctx->ctx_task = NULL; +#endif /* * There is nothing more to cleanup here. @@ -4530,6 +4870,7 @@ pfm_context_unload(pfm_context_t *ctx, v return 0; } +#ifndef XEN /* * per-task mode */ @@ -4584,9 +4925,14 @@ pfm_context_unload(pfm_context_t *ctx, v 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) @@ -5208,13 +5554,19 @@ pfm_end_notify_user(pfm_context_t *ctx) return pfm_notify_user(ctx, msg); } +#endif /* * main overflow processing routine. * it can be called from the interrupt path or explicitely during the context switch code */ +#ifndef XEN static void pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +#else +static void +pfm_overflow_handler(pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs) +#endif { pfm_ovfl_arg_t *ovfl_arg; unsigned long mask; @@ -5223,7 +5575,11 @@ pfm_overflow_handler(struct task_struct unsigned long tstamp; pfm_ovfl_ctrl_t ovfl_ctrl; unsigned int i, has_smpl; +#ifndef XEN int must_notify = 0; +#else + struct task_struct* task = NULL; +#endif if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) goto stop_monitoring; @@ -5398,6 +5754,7 @@ pfm_overflow_handler(struct task_struct } if (ovfl_notify && ovfl_ctrl.bits.notify_user) { +#ifndef XEN /* * keep track of what to reset when unblocking */ @@ -5426,11 +5783,18 @@ pfm_overflow_handler(struct task_struct * anyway, so the signal receiver would come spin for nothing. */ must_notify = 1; +#else + DPRINTK("%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, @@ -5439,15 +5803,21 @@ pfm_overflow_handler(struct task_struct * 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 + DPRINTK("%s check!\n", __func__); +#endif + } + +#ifndef XEN /* * send notification now */ if (must_notify) pfm_ovfl_notify_user(ctx, ovfl_notify); +#endif return; @@ -5497,7 +5867,9 @@ static int static int pfm_do_interrupt_handler(int irq, void *arg, struct pt_regs *regs) { +#ifndef XEN struct task_struct *task; +#endif pfm_context_t *ctx; unsigned long flags; u64 pmc0; @@ -5511,14 +5883,20 @@ pfm_do_interrupt_handler(int irq, void * */ pmc0 = ia64_get_pmc(0); +#ifndef XEN task = GET_PMU_OWNER(); +#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 */ @@ -5526,12 +5904,18 @@ pfm_do_interrupt_handler(int irq, void * /* 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); +#ifndef XEN pfm_overflow_handler(task, ctx, pmc0, regs); +#else + pfm_overflow_handler(ctx, pmc0, regs); +#endif UNPROTECT_CTX_NOPRINT(ctx, flags); @@ -5547,16 +5931,20 @@ pfm_do_interrupt_handler(int irq, void * 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 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 @@ -5595,9 +5983,12 @@ pfm_interrupt_handler(int irq, void *arg } put_cpu_no_resched(); +#ifndef XEN return IRQ_HANDLED; -} - +#endif +} + +#ifndef XEN /* * /proc/perfmon interface, for debug only */ @@ -5775,6 +6166,7 @@ pfm_proc_open(struct inode *inode, struc { return seq_open(file, &pfm_seq_ops); } +#endif /* @@ -5829,6 +6221,7 @@ pfm_syst_wide_update_task(struct task_st } } +#ifndef XEN #ifdef CONFIG_SMP static void @@ -6324,13 +6717,20 @@ pfm_load_regs (struct task_struct *task) if (likely(psr_up)) pfm_set_psr_up(); } #endif /* CONFIG_SMP */ +#endif /* * this function assumes monitoring is stopped */ +#ifndef XEN static void pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx) -{ +#else +static void +pfm_flush_pmds(pfm_context_t *ctx) +#endif +{ +#ifndef XEN u64 pmc0; unsigned long mask2, val, pmd_val, ovfl_val; int i, can_access_pmu = 0; @@ -6436,14 +6836,20 @@ pfm_flush_pmds(struct task_struct *task, 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) { @@ -6578,11 +6984,14 @@ pfm_remove_alt_pmu_interrupt(pfm_intr_ha 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); +#endif static int __init pfm_probe_pmu(void) @@ -6607,12 +7016,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) @@ -6682,6 +7093,7 @@ pfm_init(void) return -1; } +#ifndef XEN /* * create /proc/perfmon (mostly for debugging purposes) */ @@ -6700,6 +7112,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 @@ -6707,7 +7120,9 @@ pfm_init(void) spin_lock_init(&pfm_sessions.pfs_lock); spin_lock_init(&pfm_buffer_fmt_lock); +#ifndef XEN init_pfm_fs(); +#endif for(i=0; i < NR_CPUS; i++) pfm_stats[i].pfm_ovfl_intr_cycles_min = ~0UL; @@ -6766,12 +7181,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(); @@ -6806,6 +7223,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, @@ -6814,10 +7232,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. */ @@ -6841,6 +7268,7 @@ pfm_inherit(struct task_struct *task, st * 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) @@ -6848,3 +7276,586 @@ sys_perfmonctl (int fd, int cmd, void *a 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, &kreq, 1); + 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); + 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); + 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]) { + DPRINTK("%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); + 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]) { + DPRINTK("%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]) { + DPRINTK("%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) { + DPRINTK("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 -r db608db1c300 -r bd4247feec26 xen/arch/ia64/linux-xen/perfmon_default_smpl.c --- a/xen/arch/ia64/linux-xen/perfmon_default_smpl.c Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/linux-xen/perfmon_default_smpl.c Thu Oct 26 14:27:38 2006 +0900 @@ -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 * 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 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 -r db608db1c300 -r bd4247feec26 xen/arch/ia64/linux/Makefile --- a/xen/arch/ia64/linux/Makefile Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/linux/Makefile Thu Oct 26 14:27:38 2006 +0900 @@ -22,6 +22,7 @@ obj-y += __udivdi3.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 -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/Makefile --- a/xen/arch/ia64/xen/Makefile Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/xen/Makefile Thu Oct 26 14:27:38 2006 +0900 @@ -1,3 +1,5 @@ obj-y += acpi.o +subdir-y += oprofile + obj-y += acpi.o obj-y += dom0_ops.o obj-y += domain.o diff -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/dom0_ops.c --- a/xen/arch/ia64/xen/dom0_ops.c Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/xen/dom0_ops.c Thu Oct 26 14:27:38 2006 +0900 @@ -344,6 +344,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 -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/domain.c --- a/xen/arch/ia64/xen/domain.c Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/xen/domain.c Thu Oct 26 14:27:38 2006 +0900 @@ -48,6 +48,7 @@ #include #include #include +#include unsigned long dom0_size = 512*1024*1024; @@ -228,11 +229,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(); } @@ -620,6 +645,9 @@ void domain_relinquish_resources(struct 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); } void build_physmap_table(struct domain *d) diff -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/hypercall.c --- a/xen/arch/ia64/xen/hypercall.c Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/xen/hypercall.c Thu Oct 26 14:27:38 2006 +0900 @@ -68,7 +68,7 @@ const hypercall_t ia64_hypercall_table[N (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 -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/oprofile/perfmon.c --- a/xen/arch/ia64/xen/oprofile/perfmon.c Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/arch/ia64/xen/oprofile/perfmon.c Thu Oct 26 14:27:38 2006 +0900 @@ -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,171 @@ * @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) { + unsigned long ip = regs->cr_iip; int event = arg->pmd_eventid; 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); + 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; + } + } + 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 -r db608db1c300 -r bd4247feec26 xen/include/asm-ia64/config.h --- a/xen/include/asm-ia64/config.h Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/include/asm-ia64/config.h Thu Oct 26 14:27:38 2006 +0900 @@ -125,6 +125,7 @@ extern char _end[]; /* standard ELF symb // 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 @@ -271,6 +272,8 @@ struct screen_info { }; #endif /* __ASSEMBLY__ */ #endif /* __XEN_IA64_CONFIG_H__ */ +#define CONFIG_PERFMON 1 + #ifndef __ASSEMBLY__ #include #define FORCE_CRASH() asm("break.m 0;;"); diff -r db608db1c300 -r bd4247feec26 xen/include/asm-ia64/domain.h --- a/xen/include/asm-ia64/domain.h Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/include/asm-ia64/domain.h Thu Oct 26 14:27:38 2006 +0900 @@ -212,6 +212,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 -r db608db1c300 -r bd4247feec26 xen/include/asm-ia64/linux-xen/asm/perfmon.h --- a/xen/include/asm-ia64/linux-xen/asm/perfmon.h Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/include/asm-ia64/linux-xen/asm/perfmon.h Thu Oct 26 14:27:38 2006 +0900 @@ -5,6 +5,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 -r db608db1c300 -r bd4247feec26 xen/include/public/arch-ia64.h --- a/xen/include/public/arch-ia64.h Thu Oct 26 14:27:25 2006 +0900 +++ b/xen/include/public/arch-ia64.h Thu Oct 26 14:27:38 2006 +0900 @@ -355,6 +355,9 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_conte /* expose the p2m table into domain */ #define IA64_DOM0VP_expose_p2m 7 +/* xen perfmon */ +#define IA64_DOM0VP_perfmon 11 + // flags for page assignement to pseudo physical address space #define _ASSIGN_readonly 0 #define ASSIGN_readonly (1UL << _ASSIGN_readonly) @@ -438,6 +441,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__ */ /* diff -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/oprofile/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/oprofile/Makefile Thu Oct 26 14:27:38 2006 +0900 @@ -0,0 +1,1 @@ +obj-y += perfmon.o xenoprof.o diff -r db608db1c300 -r bd4247feec26 xen/arch/ia64/xen/oprofile/xenoprof.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/oprofile/xenoprof.c Thu Oct 26 14:27:38 2006 +0900 @@ -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)) { + DPRINTK("%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 -r db608db1c300 -r bd4247feec26 xen/include/asm-ia64/xenoprof.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-ia64/xenoprof.h Thu Oct 26 14:27:38 2006 +0900 @@ -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: + */