diff -up ./arch/x86/Kconfig.cpu.emuops ./arch/x86/Kconfig.cpu --- ./arch/x86/Kconfig.cpu.emuops 2026-05-29 19:06:30.674437940 +0900 +++ ./arch/x86/Kconfig.cpu 2026-05-29 19:09:36.218889284 +0900 @@ -412,6 +412,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 -up ./arch/x86/configs/i386_defconfig.emuops ./arch/x86/configs/i386_defconfig --- ./arch/x86/configs/i386_defconfig.emuops 2026-05-29 19:00:46.315560066 +0900 +++ ./arch/x86/configs/i386_defconfig 2026-05-29 19:09:36.219889287 +0900 @@ -35,6 +35,7 @@ CONFIG_SMP=y # CONFIG_GEODE_NOPL is not set # CONFIG_IGNORE_SSP_OPCODE is not set # CONFIG_CPU_EMU_FUCOMI is not set +# CONFIG_CPU_PROC_EMULATED_OPS is not set CONFIG_HYPERVISOR_GUEST=y CONFIG_PARAVIRT=y CONFIG_NR_CPUS=8 diff -up ./arch/x86/kernel/traps.c.emuops ./arch/x86/kernel/traps.c --- ./arch/x86/kernel/traps.c.emuops 2026-05-29 19:00:46.316560069 +0900 +++ ./arch/x86/kernel/traps.c 2026-05-29 19:09:36.220889289 +0900 @@ -44,6 +44,11 @@ #include #include +#ifdef CONFIG_CPU_PROC_EMULATED_OPS +#include +#include +#endif + #include #include #include @@ -812,6 +817,50 @@ static inline void *reg_address(struct p #define access_ok_read(addr,size) access_ok(VERIFY_READ, (addr),(size)) #endif +#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 proc_ops emulated_ops_proc_ops = { + .proc_open = emulated_ops_proc_open, + .proc_read = seq_read, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +static int __init proc_emulated_ops_init(void) +{ + proc_create("emulated_ops", 0, NULL, &emulated_ops_proc_ops); + return 0; +} +module_init(proc_emulated_ops_init); +#endif /* CONFIG_CPU_PROC_EMULATED_OPS } */ + /* [handle_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 @@ -877,6 +926,9 @@ static void handle_invalid_op(struct pt_ if (res) { int i = 0; do { +#ifdef CONFIG_CPU_PROC_EMULATED_OPS + emulated_ops_counter.nopl++; +#endif eip += res; i++; res = is_nopl(eip); @@ -896,6 +948,9 @@ static void handle_invalid_op(struct pt_ switch (op2 & 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 @@ -904,6 +959,9 @@ static void handle_invalid_op(struct pt_ 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 @@ -916,6 +974,9 @@ static void handle_invalid_op(struct pt_ switch (op2 & 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 @@ -924,6 +985,9 @@ static void handle_invalid_op(struct pt_ 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 @@ -936,6 +1000,9 @@ static void handle_invalid_op(struct pt_ if ((op1 & 0xFE) == 0xDA && (op2 & 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, op1, op2); #endif @@ -998,6 +1065,9 @@ static void handle_invalid_op(struct pt_ get_user(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 */