lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Message-ID: <20140721224039.5d8b5faa@gandalf.local.home> Date: Mon, 21 Jul 2014 22:40:39 -0400 From: Steven Rostedt <rostedt@...dmis.org> To: Borislav Petkov <bp@...en8.de> Cc: Peter Zijlstra <peterz@...radead.org>, Thomas Gleixner <tglx@...utronix.de>, x86-ml <x86@...nel.org>, lkml <linux-kernel@...r.kernel.org> Subject: Re: [PATCH] x86, TSC: Add a software TSC offset Your patch inspired me to write this hack. I was curious to know how the TSCs of my boxes were with respect to each other, and wanted to get an idea. Maybe there's a better way, but I decided to waste an hour and write this hack up. Here's what it does. It creates the file /sys/kernel/debug/rdtsc_test, and when you read it, it does some whacky things. 1) A table is set up with the number of possible CPUs. The cable consists of: index, TSC count, CPU. 2) A atomic variable is set to the number of online CPUS. 3) An IPI is sent to each of the other CPUs to run the test. 4) The test decrements the atomic, and then spins until it reaches zero. 5) The caller of smp_call_function() then calls the test iself, being the last to decrement the counter causing it to go to zero and all CPUs then fight for a spinlock. 6) When the spin lock is taken, it records which place it was in (order of spinlock taken, and records its own TSC. Then it releases the lock. 7) It then records in the table where its position is, its TSC counter and CPU number. Finally, the read will show the results of the table. Looks something like this: # cat /debug/rdtsc_test 0) 1305910016816 (cpu:5) 1) 1305910017550 (cpu:7) 2) 1305910017712 (cpu:1) 3) 1305910017910 (cpu:6) 4) 1305910018042 (cpu:2) 5) 1305910018226 (cpu:3) 6) 1305910018416 (cpu:4) 7) 1305910018540 (cpu:0) As long as the TSC counts are in order of the index, the TSC is moving forward nicely. If they are not in order, then the TSCs are not in sync. Yes, this is a hack, but I think it's a somewhat useful hack. Not-for-inclusion-by: Steven Rostedt <rostedt@...dmis.org> --- kernel/Makefile | 1 kernel/rdtsc_test.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) Index: linux-trace.git/kernel/Makefile =================================================================== --- linux-trace.git.orig/kernel/Makefile 2014-07-16 14:10:47.210980652 -0400 +++ linux-trace.git/kernel/Makefile 2014-07-21 18:23:23.990246141 -0400 @@ -28,6 +28,7 @@ obj-y += irq/ obj-y += rcu/ +obj-$(CONFIG_DEBUG_FS) += rdtsc_test.o obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o obj-$(CONFIG_FREEZER) += freezer.o obj-$(CONFIG_PROFILING) += profile.o Index: linux-trace.git/kernel/rdtsc_test.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-trace.git/kernel/rdtsc_test.c 2014-07-21 22:32:16.531878062 -0400 @@ -0,0 +1,127 @@ +#include <linux/spinlock.h> +#include <linux/seq_file.h> +#include <linux/debugfs.h> +#include <linux/percpu.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/cpu.h> + +static unsigned int rdtsc_count __read_mostly; +static unsigned int rdtsc_index; +static u64 *rdtsc_counts; +static unsigned int *rdtsc_cpus; + +static DEFINE_RAW_SPINLOCK(rdtsc_lock); +static DEFINE_MUTEX(rdtsc_mutex); + +static atomic_t rdtsc_start; + +static void read_rdtsc_test(void *data) +{ + unsigned int idx; + u64 cnt; + + atomic_dec(&rdtsc_start); + while (atomic_read(&rdtsc_start)) + cpu_relax(); + + raw_spin_lock(&rdtsc_lock); + idx = rdtsc_index++; + rdtscll(cnt); + raw_spin_unlock(&rdtsc_lock); + + if (idx >= rdtsc_count) + return; + + rdtsc_counts[idx] = cnt; + rdtsc_cpus[idx] = smp_processor_id(); +} + +static void run_rdtsc_test(void) +{ + int i = 0; + + get_online_cpus(); + mutex_lock(&rdtsc_mutex); + atomic_set(&rdtsc_start, num_online_cpus()); + rdtsc_index = 0; + memset(rdtsc_counts, 0, sizeof(*rdtsc_counts) * rdtsc_count); + memset(rdtsc_cpus, 0, sizeof(*rdtsc_cpus) * rdtsc_count); + + /* Don't let us get migrated */ + preempt_disable(); + smp_call_function(read_rdtsc_test, NULL, 0); + + /* Run the test without being disturbed. */ + local_irq_disable(); + read_rdtsc_test(NULL); + local_irq_enable(); + + preempt_enable(); + + /* We didn't wait for smp_call_function() to complete on other CPUS */ + while (rdtsc_index < num_online_cpus() && i++ < 1000) + msleep(1); + + mutex_unlock(&rdtsc_mutex); + WARN_ON(rdtsc_index < num_online_cpus()); + put_online_cpus(); +} + +static int rdtsc_test_show(struct seq_file *m, void *v) +{ + unsigned int i; + + mutex_lock(&rdtsc_mutex); + + for (i = 0; i < rdtsc_count; i++) { + seq_printf(m, "%5u) %9llu (cpu:%u)\n", + i, rdtsc_counts[i], rdtsc_cpus[i]); + } + + mutex_unlock(&rdtsc_mutex); + + return 0; +} + +static int rdtsc_test_open(struct inode *inode, struct file *filp) +{ + run_rdtsc_test(); + + return single_open(filp, rdtsc_test_show, inode->i_private); +} + +static const struct file_operations rdtsc_test_fops = { + .open = rdtsc_test_open, + .read = seq_read, + .llseek = generic_file_llseek, +}; + +static __init int init_rdtsc_test(void) +{ + struct dentry *ret; + + rdtsc_count = num_possible_cpus(); + rdtsc_counts = kmalloc(sizeof(*rdtsc_counts) * rdtsc_count, GFP_KERNEL); + if (!rdtsc_counts) { + pr_warn("Could not create rdtsc_test counts\n"); + return -ENOMEM; + } + + rdtsc_cpus = kmalloc(sizeof(*rdtsc_cpus) * rdtsc_count, GFP_KERNEL); + if (!rdtsc_cpus) { + kfree(rdtsc_counts); + pr_warn("Could not create rdtsc_test cpus\n"); + return -ENOMEM; + } + + ret = debugfs_create_file("rdtsc_test", 0x400, NULL, NULL, + &rdtsc_test_fops); + if (!ret) + pr_warn("Could not create debugfs rdtsc_test entry\n"); + return ret; +} + +fs_initcall(init_rdtsc_test); + -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@...r.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists