diff options
Diffstat (limited to 'arch/arm/oprofile')
-rw-r--r-- | arch/arm/oprofile/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/oprofile/backtrace.c | 46 | ||||
-rw-r--r-- | arch/arm/oprofile/common.c | 185 | ||||
-rw-r--r-- | arch/arm/oprofile/init.c | 33 | ||||
-rw-r--r-- | arch/arm/oprofile/op_arm_model.h | 4 |
5 files changed, 110 insertions, 162 deletions
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile index 8ffb523e6c7..6a94e54848f 100644 --- a/arch/arm/oprofile/Makefile +++ b/arch/arm/oprofile/Makefile @@ -6,6 +6,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ oprofilefs.o oprofile_stats.o \ timer_int.o ) -oprofile-y := $(DRIVER_OBJS) init.o backtrace.o -oprofile-$(CONFIG_CPU_XSCALE) += common.o op_model_xscale.o +oprofile-y := $(DRIVER_OBJS) common.o backtrace.o +oprofile-$(CONFIG_CPU_XSCALE) += op_model_xscale.o diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c index df35c452a8b..7c22c12618c 100644 --- a/arch/arm/oprofile/backtrace.c +++ b/arch/arm/oprofile/backtrace.c @@ -49,42 +49,22 @@ static struct frame_tail* kernel_backtrace(struct frame_tail *tail) static struct frame_tail* user_backtrace(struct frame_tail *tail) { - struct frame_tail buftail; + struct frame_tail buftail[2]; - /* hardware pte might not be valid due to dirty/accessed bit emulation - * so we use copy_from_user and benefit from exception fixups */ - if (copy_from_user(&buftail, tail, sizeof(struct frame_tail))) + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) + return NULL; + if (__copy_from_user_inatomic(buftail, tail, sizeof(buftail))) return NULL; - oprofile_add_trace(buftail.lr); + oprofile_add_trace(buftail[0].lr); /* frame pointers should strictly progress back up the stack * (towards higher addresses) */ - if (tail >= buftail.fp) + if (tail >= buftail[0].fp) return NULL; - return buftail.fp-1; -} - -/* Compare two addresses and see if they're on the same page */ -#define CMP_ADDR_EQUAL(x,y,offset) ((((unsigned long) x) >> PAGE_SHIFT) \ - == ((((unsigned long) y) + offset) >> PAGE_SHIFT)) - -/* check that the page(s) containing the frame tail are present */ -static int pages_present(struct frame_tail *tail) -{ - struct mm_struct * mm = current->mm; - - if (!check_user_page_readable(mm, (unsigned long)tail)) - return 0; - - if (CMP_ADDR_EQUAL(tail, tail, 8)) - return 1; - - if (!check_user_page_readable(mm, ((unsigned long)tail) + 8)) - return 0; - - return 1; + return buftail[0].fp-1; } /* @@ -118,7 +98,6 @@ static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs) void arm_backtrace(struct pt_regs * const regs, unsigned int depth) { struct frame_tail *tail; - unsigned long last_address = 0; tail = ((struct frame_tail *) regs->ARM_fp) - 1; @@ -132,13 +111,6 @@ void arm_backtrace(struct pt_regs * const regs, unsigned int depth) return; } - while (depth-- && tail && !((unsigned long) tail & 3)) { - if ((!CMP_ADDR_EQUAL(last_address, tail, 0) - || !CMP_ADDR_EQUAL(last_address, tail, 8)) - && !pages_present(tail)) - return; - last_address = (unsigned long) tail; + while (depth-- && tail && !((unsigned long) tail & 3)) tail = user_backtrace(tail); - } } - diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index e57dde88289..1415930ceee 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -10,74 +10,23 @@ #include <linux/init.h> #include <linux/oprofile.h> #include <linux/errno.h> -#include <asm/semaphore.h> #include <linux/sysdev.h> +#include <asm/semaphore.h> #include "op_counter.h" #include "op_arm_model.h" -static struct op_arm_model_spec *pmu_model; -static int pmu_enabled; -static struct semaphore pmu_sem; - -static int pmu_start(void); -static int pmu_setup(void); -static void pmu_stop(void); -static int pmu_create_files(struct super_block *, struct dentry *); - -#ifdef CONFIG_PM -static int pmu_suspend(struct sys_device *dev, pm_message_t state) -{ - if (pmu_enabled) - pmu_stop(); - return 0; -} - -static int pmu_resume(struct sys_device *dev) -{ - if (pmu_enabled) - pmu_start(); - return 0; -} - -static struct sysdev_class oprofile_sysclass = { - set_kset_name("oprofile"), - .resume = pmu_resume, - .suspend = pmu_suspend, -}; - -static struct sys_device device_oprofile = { - .id = 0, - .cls = &oprofile_sysclass, -}; - -static int __init init_driverfs(void) -{ - int ret; - - if (!(ret = sysdev_class_register(&oprofile_sysclass))) - ret = sysdev_register(&device_oprofile); - - return ret; -} - -static void exit_driverfs(void) -{ - sysdev_unregister(&device_oprofile); - sysdev_class_unregister(&oprofile_sysclass); -} -#else -#define init_driverfs() do { } while (0) -#define exit_driverfs() do { } while (0) -#endif /* CONFIG_PM */ +static struct op_arm_model_spec *op_arm_model; +static int op_arm_enabled; +static struct semaphore op_arm_sem; struct op_counter_config counter_config[OP_MAX_COUNTER]; -static int pmu_create_files(struct super_block *sb, struct dentry *root) +static int op_arm_create_files(struct super_block *sb, struct dentry *root) { unsigned int i; - for (i = 0; i < pmu_model->num_counters; i++) { + for (i = 0; i < op_arm_model->num_counters; i++) { struct dentry *dir; char buf[2]; @@ -94,63 +43,123 @@ static int pmu_create_files(struct super_block *sb, struct dentry *root) return 0; } -static int pmu_setup(void) +static int op_arm_setup(void) { int ret; spin_lock(&oprofilefs_lock); - ret = pmu_model->setup_ctrs(); + ret = op_arm_model->setup_ctrs(); spin_unlock(&oprofilefs_lock); return ret; } -static int pmu_start(void) +static int op_arm_start(void) { int ret = -EBUSY; - down(&pmu_sem); - if (!pmu_enabled) { - ret = pmu_model->start(); - pmu_enabled = !ret; + down(&op_arm_sem); + if (!op_arm_enabled) { + ret = op_arm_model->start(); + op_arm_enabled = !ret; } - up(&pmu_sem); + up(&op_arm_sem); return ret; } -static void pmu_stop(void) +static void op_arm_stop(void) +{ + down(&op_arm_sem); + if (op_arm_enabled) + op_arm_model->stop(); + op_arm_enabled = 0; + up(&op_arm_sem); +} + +#ifdef CONFIG_PM +static int op_arm_suspend(struct sys_device *dev, pm_message_t state) { - down(&pmu_sem); - if (pmu_enabled) - pmu_model->stop(); - pmu_enabled = 0; - up(&pmu_sem); + down(&op_arm_sem); + if (op_arm_enabled) + op_arm_model->stop(); + up(&op_arm_sem); + return 0; } -int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec) +static int op_arm_resume(struct sys_device *dev) { - init_MUTEX(&pmu_sem); + down(&op_arm_sem); + if (op_arm_enabled && op_arm_model->start()) + op_arm_enabled = 0; + up(&op_arm_sem); + return 0; +} + +static struct sysdev_class oprofile_sysclass = { + set_kset_name("oprofile"), + .resume = op_arm_resume, + .suspend = op_arm_suspend, +}; - if (spec->init() < 0) - return -ENODEV; +static struct sys_device device_oprofile = { + .id = 0, + .cls = &oprofile_sysclass, +}; - pmu_model = spec; - init_driverfs(); - ops->create_files = pmu_create_files; - ops->setup = pmu_setup; - ops->shutdown = pmu_stop; - ops->start = pmu_start; - ops->stop = pmu_stop; - ops->cpu_type = pmu_model->name; - printk(KERN_INFO "oprofile: using %s PMU\n", spec->name); +static int __init init_driverfs(void) +{ + int ret; - return 0; + if (!(ret = sysdev_class_register(&oprofile_sysclass))) + ret = sysdev_register(&device_oprofile); + + return ret; +} + +static void exit_driverfs(void) +{ + sysdev_unregister(&device_oprofile); + sysdev_class_unregister(&oprofile_sysclass); +} +#else +#define init_driverfs() do { } while (0) +#define exit_driverfs() do { } while (0) +#endif /* CONFIG_PM */ + +int __init oprofile_arch_init(struct oprofile_operations *ops) +{ + struct op_arm_model_spec *spec = NULL; + int ret = -ENODEV; + +#ifdef CONFIG_CPU_XSCALE + spec = &op_xscale_spec; +#endif + + if (spec) { + init_MUTEX(&op_arm_sem); + + if (spec->init() < 0) + return -ENODEV; + + op_arm_model = spec; + init_driverfs(); + ops->create_files = op_arm_create_files; + ops->setup = op_arm_setup; + ops->shutdown = op_arm_stop; + ops->start = op_arm_start; + ops->stop = op_arm_stop; + ops->cpu_type = op_arm_model->name; + ops->backtrace = arm_backtrace; + printk(KERN_INFO "oprofile: using %s\n", spec->name); + } + + return ret; } -void pmu_exit(void) +void oprofile_arch_exit(void) { - if (pmu_model) { + if (op_arm_model) { exit_driverfs(); - pmu_model = NULL; + op_arm_model = NULL; } } diff --git a/arch/arm/oprofile/init.c b/arch/arm/oprofile/init.c deleted file mode 100644 index d315a3a86c8..00000000000 --- a/arch/arm/oprofile/init.c +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file init.c - * - * @remark Copyright 2004 Oprofile Authors - * @remark Read the file COPYING - * - * @author Zwane Mwaikambo - */ - -#include <linux/oprofile.h> -#include <linux/init.h> -#include <linux/errno.h> -#include "op_arm_model.h" - -int __init oprofile_arch_init(struct oprofile_operations *ops) -{ - int ret = -ENODEV; - -#ifdef CONFIG_CPU_XSCALE - ret = pmu_init(ops, &op_xscale_spec); -#endif - - ops->backtrace = arm_backtrace; - - return ret; -} - -void oprofile_arch_exit(void) -{ -#ifdef CONFIG_CPU_XSCALE - pmu_exit(); -#endif -} diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h index 2148d07484b..38c6ad15854 100644 --- a/arch/arm/oprofile/op_arm_model.h +++ b/arch/arm/oprofile/op_arm_model.h @@ -26,6 +26,6 @@ extern struct op_arm_model_spec op_xscale_spec; extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth); -extern int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec); -extern void pmu_exit(void); +extern int __init op_arm_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec); +extern void op_arm_exit(void); #endif /* OP_ARM_MODEL_H */ |