diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index 37bca3f..1e0f0e4 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -382,6 +382,15 @@ config CPU_EMU_FUCOMI If you are not sure, say N. +config CPU_PROC_EMULATED_OPS + bool "/proc/emulated_ops support" + depends on X86_32 && CPU_EMU486 + ---help--- + /proc/emulated_ops will show counts of emulated + CMOV, NOPL, FCOMI/FCOMIP, FUCOMI/FUCOMIP and FCMOVcc instructions. + + If you are not sure, say N. + config CPU_EMU486_DEBUG bool "Emulation debug" depends on X86_32 && CPU_EMU486 diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index ab362b2..c7c8534 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -44,6 +44,7 @@ CONFIG_X86_GENERIC=y # CONFIG_CPU_EMU486_DEBUG is not set # CONFIG_GEODE_NOPL is not set # CONFIG_CPU_EMU_FUCOMI is not set +# CONFIG_CPU_PROC_EMULATED_OPS is not set CONFIG_HPET_TIMER=y CONFIG_SCHED_SMT=y CONFIG_PREEMPT_VOLUNTARY=y diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 16e0736..056206b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -45,6 +45,11 @@ #include #endif +#ifdef CONFIG_CPU_PROC_EMULATED_OPS +#include +#include +#endif + #include #include #include @@ -849,6 +854,50 @@ static inline void *reg_address(struct pt_regs *regs, char w, u8 reg) return NULL; } +#ifdef CONFIG_CPU_PROC_EMULATED_OPS +static struct { + unsigned long cmov; + unsigned long nopl; + unsigned long fcomi; + unsigned long fucomi; + unsigned long fcmov; +} emulated_ops_counter = { + 0, 0, 0, 0, 0 +}; +static int emulated_ops_proc_show(struct seq_file *m, void *v) +{ +#if defined(CONFIG_CPU_EMU686) + seq_printf(m, "cmov: %lu\n", emulated_ops_counter.cmov); +#endif +#ifdef CONFIG_GEODE_NOPL + seq_printf(m, "nopl: %lu\n", emulated_ops_counter.nopl); +#endif +#ifdef CONFIG_CPU_EMU_FUCOMI + seq_printf(m, "fcomi: %lu\n" "fucomi: %lu\n" "fcmov: %lu\n", + emulated_ops_counter.fcomi, + emulated_ops_counter.fucomi, + emulated_ops_counter.fcmov); +#endif + return 0; +} +static int emulated_ops_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, emulated_ops_proc_show, NULL); +} +static const struct file_operations emulated_ops_proc_fops = { + .open = emulated_ops_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +static int __init proc_emulated_ops_init(void) +{ + proc_create("emulated_ops", 0, NULL, &emulated_ops_proc_fops); + return 0; +} +module_init(proc_emulated_ops_init); +#endif /* CONFIG_CPU_PROC_EMULATED_OPS */ + /* [do_invalid_op] is called by exception 6 after an invalid opcode has been * encountered. It will decode the prefixes and the instruction code, to try * to emulate it, and will send a SIGILL or SIGSEGV to the process if not @@ -884,6 +933,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) if (res) { int i = 0; do { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.nopl++; +#endif eip += res; i++; res = is_nopl(eip); @@ -903,6 +955,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) switch (eip[1] & 0xF8) { case 0xF0: /* FCOMI */ if (do_fcomi(regs)) { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.fcomi++; +#endif #ifdef CONFIG_CPU_FUCOMI_DEBUG printk(KERN_DEBUG "fcomi: emulated@%08x\n", eip); #endif @@ -911,6 +966,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) break; case 0xE8: /* FUCOMI */ if (do_fucomi(regs)) { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.fucomi++; +#endif #ifdef CONFIG_CPU_FUCOMI_DEBUG printk(KERN_DEBUG "fucomi: emulated@%08x\n", eip); #endif @@ -923,6 +981,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) switch (eip[1] & 0xF8) { case 0xF0: /* FCOMIP */ if (do_fcomip(regs)) { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.fcomi++; +#endif #ifdef CONFIG_CPU_FUCOMI_DEBUG printk(KERN_DEBUG "fcomip: emulated@%08x\n", eip); #endif @@ -931,6 +992,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) break; case 0xE8: /* FUCOMIP */ if (do_fucomip(regs)) { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.fucomi++; +#endif #ifdef CONFIG_CPU_FUCOMI_DEBUG printk(KERN_DEBUG "fucomip: emulated@%08x\n", eip); #endif @@ -943,6 +1007,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) if ((eip[0] & 0xFE) == 0xDA && (eip[1] & 0xE0) == 0xC0) { /* FCMOVcc */ int res = do_fcmov(regs); if (res) { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.fcmov++; +#endif #ifdef CONFIG_CPU_FUCOMI_DEBUG printk(KERN_DEBUG "fcmov: emulated@%08x %02x %02x\n", eip, eip[0], eip[1]); #endif @@ -1001,6 +1068,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) modrm = *(eip + 1); eip += 2; /* skips all the opcodes */ +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.cmov++; +#endif if (!ncond) { /* condition is not valid, skip the instruction and do nothing */