sh: wire up perf alignment and emulation faults.

This plugs in the alignment and emulation fault reporting for perf sw
events.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Paul Mundt 2010-10-13 06:55:26 +09:00
parent 5a30d7bfcd
commit ace2dc7d12
5 changed files with 33 additions and 9 deletions

View File

@ -212,7 +212,7 @@ static inline reg_size_t register_align(void *val)
} }
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
struct mem_access *ma, int); struct mem_access *ma, int, unsigned long address);
static inline void trigger_address_error(void) static inline void trigger_address_error(void)
{ {

View File

@ -291,7 +291,7 @@ int handle_trapped_io(struct pt_regs *regs, unsigned long address)
} }
tmp = handle_unaligned_access(instruction, regs, tmp = handle_unaligned_access(instruction, regs,
&trapped_io_access, 1); &trapped_io_access, 1, address);
set_fs(oldfs); set_fs(oldfs);
return tmp == 0; return tmp == 0;
} }

View File

@ -5,7 +5,7 @@
* SuperH version: Copyright (C) 1999 Niibe Yutaka * SuperH version: Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf * Copyright (C) 2000 Philipp Rumpf
* Copyright (C) 2000 David Howells * Copyright (C) 2000 David Howells
* Copyright (C) 2002 - 2007 Paul Mundt * Copyright (C) 2002 - 2010 Paul Mundt
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
@ -26,6 +26,7 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/perf_event.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/alignment.h> #include <asm/alignment.h>
#include <asm/fpu.h> #include <asm/fpu.h>
@ -369,7 +370,8 @@ static inline int handle_delayslot(struct pt_regs *regs,
#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) #define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
struct mem_access *ma, int expected) struct mem_access *ma, int expected,
unsigned long address)
{ {
u_int rm; u_int rm;
int ret, index; int ret, index;
@ -383,9 +385,18 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
index = (instruction>>8)&15; /* 0x0F00 */ index = (instruction>>8)&15; /* 0x0F00 */
rm = regs->regs[index]; rm = regs->regs[index];
/* shout about fixups */ /*
if (!expected) * Log the unexpected fixups, and then pass them on to perf.
*
* We intentionally don't report the expected cases to perf as
* otherwise the trapped I/O case will skew the results too much
* to be useful.
*/
if (!expected) {
unaligned_fixups_notify(current, instruction, regs); unaligned_fixups_notify(current, instruction, regs);
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0,
regs, address);
}
ret = -EFAULT; ret = -EFAULT;
switch (instruction&0xF000) { switch (instruction&0xF000) {
@ -574,7 +585,8 @@ fixup:
set_fs(USER_DS); set_fs(USER_DS);
tmp = handle_unaligned_access(instruction, regs, tmp = handle_unaligned_access(instruction, regs,
&user_mem_access, 0); &user_mem_access, 0,
address);
set_fs(oldfs); set_fs(oldfs);
if (tmp == 0) if (tmp == 0)
@ -607,8 +619,8 @@ uspace_segv:
unaligned_fixups_notify(current, instruction, regs); unaligned_fixups_notify(current, instruction, regs);
handle_unaligned_access(instruction, regs, handle_unaligned_access(instruction, regs, &user_mem_access,
&user_mem_access, 0); 0, address);
set_fs(oldfs); set_fs(oldfs);
} }
} }

View File

@ -24,6 +24,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/perf_event.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
@ -433,6 +434,8 @@ static int misaligned_load(struct pt_regs *regs,
return error; return error;
} }
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
destreg = (opcode >> 4) & 0x3f; destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) { if (user_mode(regs)) {
__u64 buffer; __u64 buffer;
@ -509,6 +512,8 @@ static int misaligned_store(struct pt_regs *regs,
return error; return error;
} }
perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, 0, regs, address);
srcreg = (opcode >> 4) & 0x3f; srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) { if (user_mode(regs)) {
__u64 buffer; __u64 buffer;
@ -583,6 +588,8 @@ static int misaligned_fpu_load(struct pt_regs *regs,
return error; return error;
} }
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
destreg = (opcode >> 4) & 0x3f; destreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) { if (user_mode(regs)) {
__u64 buffer; __u64 buffer;
@ -658,6 +665,8 @@ static int misaligned_fpu_store(struct pt_regs *regs,
return error; return error;
} }
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, address);
srcreg = (opcode >> 4) & 0x3f; srcreg = (opcode >> 4) & 0x3f;
if (user_mode(regs)) { if (user_mode(regs)) {
__u64 buffer; __u64 buffer;

View File

@ -12,6 +12,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/perf_event.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -619,6 +620,8 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
struct task_struct *tsk = current; struct task_struct *tsk = current;
struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu); struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
if (!(task_thread_info(tsk)->status & TS_USEDFPU)) { if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
/* initialize once. */ /* initialize once. */
fpu_init(fpu); fpu_init(fpu);