diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 9fa39e6..44f57bd 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -772,6 +772,13 @@ and is between 256 and 4096 characters. It is defined in the file kexec loader will pass this option to capture kernel. See Documentation/kdump/kdump.txt for details. + emulated_files=1 [X86_32] + if CONFIG_CPU_PROC_EMULATED_FILES is set, + start runnung /proc/emulated_files at 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] The kernel tries to adjust MTRR layout from continuous to discrete, to make X server driver able to add WB diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu index da60b08..0176a42 100644 --- a/arch/x86/Kconfig.cpu +++ b/arch/x86/Kconfig.cpu @@ -400,6 +400,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 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 --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig index 4f76abf..74b82d0 100644 --- a/arch/x86/configs/i386_defconfig +++ b/arch/x86/configs/i386_defconfig @@ -257,6 +257,7 @@ CONFIG_X86_XADD=y # CONFIG_GEODE_NOPL 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_X86_WP_WORKS_OK=y CONFIG_X86_INVLPG=y CONFIG_X86_BSWAP=y diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 8676687..17e2613 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -878,6 +878,190 @@ static int __init proc_emulated_ops_init(void) module_init(proc_emulated_ops_init); #endif /* CONFIG_CPU_PROC_EMULATED_OPS */ +#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; +/* kernel 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; + + /* + * Do not print if we are in atomic + * contexts (in exception stacks, etc.): + */ + if (preempt_count()) + return; + + down_read(&mm->mmap_sem); + 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 = d_path(&f->f_path, 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 ( ;immap_sem); +} + +static int emulated_files_proc_show(struct seq_file *m, void *v) +{ + int i; + seq_printf(m, "%10s %10s %10s %s%s\n", "cmov","sse","sse2","filename", + (!emulated_files_running)?" (stopped; write \"1\" to start)":" (write - to stop)" + ); + for (i=0;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 file_operations emulated_files_proc_fops = { + .open = emulated_files_proc_open, + .read = seq_read, + .write = emulated_files_proc_write, + .llseek = seq_lseek, + .release = single_release, +}; +static int __init proc_emulated_files_init(void) +{ + emulated_files_clear(); + proc_create("emulated_files", 0644, NULL, &emulated_files_proc_fops); + return 0; +} +module_init(proc_emulated_files_init); +#endif /* CONFIG_CPU_PROC_EMULATED_FILES */ + /* [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 @@ -993,6 +1177,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) #ifdef CONFIG_CPU_FUCOMI_DEBUG printk(KERN_DEBUG "fcmov: emulated@%08x %02x %02x\n", eip, eip[0], eip[1]); #endif +#ifdef CONFIG_CPU_PROC_EMULATED_FILES + emulated_files_byip((unsigned long)eip, OP_CMOV); +#endif return; } } @@ -1051,6 +1238,9 @@ dotraplinkage void do_invalid_op(struct pt_regs *regs, long error_code) #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 if (!ncond) { /* condition is not valid, skip the instruction and do nothing */