diff -up ./Documentation/admin-guide/kernel-parameters.txt.emfiles ./Documentation/admin-guide/kernel-parameters.txt --- ./Documentation/admin-guide/kernel-parameters.txt.emfiles 2026-05-29 19:43:56.436070764 +0900 +++ ./Documentation/admin-guide/kernel-parameters.txt 2026-05-29 19:45:30.866387785 +0900 @@ -1508,6 +1508,13 @@ kexec loader will pass this option to capture kernel. See Documentation/admin-guide/kdump/kdump.rst for details. + emulated_files=1 [X86_32] + if CONFIG_CPU_PROC_EMULATED_FILES is set, + start collecting /proc/emulated_files counts on boot. + Normally, it is not run until expcilitly enabled + by 'echo 1 > /proc/emulated_files', since the + data collection is a very heavy task on CPU. + enable_mtrr_cleanup [X86,EARLY] The kernel tries to adjust MTRR layout from continuous to discrete, to make X server driver able to add WB diff -up ./arch/x86/Kconfig.cpu.emfiles ./arch/x86/Kconfig.cpu --- ./arch/x86/Kconfig.cpu.emfiles 2026-05-29 19:15:32.788966974 +0900 +++ ./arch/x86/Kconfig.cpu 2026-05-29 19:43:56.437070767 +0900 @@ -436,6 +436,19 @@ config CPU_PROC_EMULATED_OPS If you are not sure, say N. +config CPU_PROC_EMULATED_FILES + bool "/proc/emulated_files support" + depends on CPU_PROC_EMULATED_OPS + default n + help + /proc/emulated_files will show statistics of what executable uses + emulated CMOV, SSE and SSE2 instructions. + Since this is heavy on CPU, by default data collecting is off; + explicitly enable it by "echo 1 > /proc/emulated_files" or + passing "emulated_files=1" kernel command line option. + + 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.emfiles ./arch/x86/configs/i386_defconfig --- ./arch/x86/configs/i386_defconfig.emfiles 2026-05-29 19:09:36.219889287 +0900 +++ ./arch/x86/configs/i386_defconfig 2026-05-29 19:43:56.437070767 +0900 @@ -36,6 +36,7 @@ CONFIG_SMP=y # CONFIG_IGNORE_SSP_OPCODE is not set # CONFIG_CPU_EMU_FUCOMI is not set # CONFIG_CPU_PROC_EMULATED_OPS is not set +# CONFIG_CPU_PROC_EMULATED_FILES is not set CONFIG_HYPERVISOR_GUEST=y CONFIG_PARAVIRT=y CONFIG_NR_CPUS=8 diff -up ./arch/x86/kernel/traps.c.emfiles ./arch/x86/kernel/traps.c --- ./arch/x86/kernel/traps.c.emfiles 2026-05-29 19:39:20.411185134 +0900 +++ ./arch/x86/kernel/traps.c 2026-05-29 19:43:56.439070774 +0900 @@ -893,9 +893,196 @@ static int __init proc_emulated_ops_init module_init(proc_emulated_ops_init); #endif /* CONFIG_CPU_PROC_EMULATED_OPS } */ -#ifdef CONFIG_CPU_EMU_SSE2 +#ifdef CONFIG_CPU_PROC_EMULATED_FILES /*{*/ +/* + * /proc/emulated_files support. + * Dumps list of "cmov-ops sse-ops sse2-ops /path/of/lib-or-exec" since boot. + * Is a heavy process on slow CPUs. + */ +#define EMU_OPS_FILES_MAX 1024 +struct { + char buf[256]; + unsigned long cmov; + unsigned long sse; + unsigned long sse2; +} emulated_files_list[EMU_OPS_FILES_MAX] = { + { {'\0'}, 0,0,0 }, +}; +enum emulated_op_type { + OP_NONE = 0, + OP_CMOV, + OP_SSE, + OP_SSE2, +}; +static int emulated_files_running = 0; +/* cmdline: emulated_files=1 to start /proc/emulated_files on boot */ +core_param(emulated_files, emulated_files_running, int, 0644); + +static void emulated_files_clear(void) +{ + int i; + for (i=0; imm; + struct vm_area_struct *vma; + + /* + * we might be running from an atomic context so we cannot sleep + */ + if (!mmap_read_trylock(mm)) + return; + + vma = find_vma(mm, ip); + if (vma && vma->vm_file) { + struct file *f = vma->vm_file; + char *buf = (char *)__get_free_page(GFP_KERNEL); + if (buf) { + char *p; + int i; + char *ph; + int h; + + p = file_path(f, buf, PAGE_SIZE); + if (IS_ERR(p)) + p = "?"; + + /* hash the path */ + for (h=0,ph=p; *ph!='\0'; ph++) + h += (int)*ph; + h &= 127; + i = h * (EMU_OPS_FILES_MAX / 128); + /* linear search in emulated_files_list[] for matching or vacant slot */ + for ( ;i /proc/emulated_files" + * stop by "echo - > /proc/emulated_files" + * clear by "echo 0 > /proc/emulated_files" + */ +static ssize_t emulated_files_proc_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + if (count) { + char c; + if (get_user(c, buf)) + return -EFAULT; + + switch(c) { + case '-': + emulated_files_running = 0; /* false */ + break; + case '0': + /*printk(KERN_NOTICE "clear /proc/emulated_files\n");*/ + emulated_files_clear(); + break; + case '1': + emulated_files_running = 1; /* true */ + break; + default: + return count; + } + } + return count; +} + +static const struct proc_ops emulated_files_proc_pops = { + .proc_open = emulated_files_proc_open, + .proc_read = seq_read, + .proc_write = emulated_files_proc_write, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; +static int __init proc_emulated_files_init(void) +{ + emulated_files_clear(); + proc_create("emulated_files", 0644, NULL, &emulated_files_proc_pops); + return 0; +} +module_init(proc_emulated_files_init); +#endif /* CONFIG_CPU_PROC_EMULATED_FILES } */ + +#ifdef CONFIG_CPU_PROC_EMULATED_OPS +# ifdef CONFIG_CPU_PROC_EMULATED_FILES +#define EMU_COUNT_SSE(eip) emulated_files_byip(((unsigned long)(eip)), OP_SSE); emulated_ops_counter.sse++ +#define EMU_COUNT_SSE2(eip) emulated_files_byip(((unsigned long)(eip)), OP_SSE2);emulated_ops_counter.sse2++ +# else #define EMU_COUNT_SSE(eip) emulated_ops_counter.sse++ #define EMU_COUNT_SSE2(eip) emulated_ops_counter.sse2++ +# endif #else #define EMU_COUNT_SSE(eip) #define EMU_COUNT_SSE2(eip) @@ -1427,10 +1614,13 @@ static void handle_invalid_op(struct pt_ /* ncond is now true if the cond matches the opcode */ get_user(modrm, eip+1); - eip += 2; /* skips all the opcodes */ #ifdef CONFIG_CPU_PROC_EMULATED_OPS emulated_ops_counter.cmov++; #endif +#ifdef CONFIG_CPU_PROC_EMULATED_FILES + emulated_files_byip((unsigned long)eip, OP_CMOV); +#endif + eip += 2; /* skips all the opcodes */ if (!ncond) { /* condition is not valid, skip the instruction and do nothing */