x86: fast core_id() option
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 18 Jul 2013 23:42:11 +0000 (16:42 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 19 Jul 2013 23:56:42 +0000 (16:56 -0700)
Implements core_id() with rdtscp.  VM support for rdtscp can be a bit
spotty.  If you want to run with this, try it once without, and see if
the kernel detects support for rdtscp (in the bootup output).  If so,
you're good to go.

kern/arch/x86/Kconfig
kern/arch/x86/arch.h
kern/arch/x86/cpuinfo.c
kern/arch/x86/smp_boot.c
kern/arch/x86/x86.h

index bc112c4..cb05eb7 100644 (file)
@@ -24,6 +24,15 @@ config NOFASTCALL_FSBASE
                setting FS base from userspace, you can say y to disable the fastcall
                for a slight improvement for all syscalls.  If unsure, say n.
 
+config FAST_COREID
+       bool "Fast core_id() via rdtscp"
+       default n
+       help
+               Uses rdtscp for a faster core_id() call.  Requires a relatively recent
+               microarchitecture (Nehalem).  Also, in my experience, qemu's support
+               for rdtscp on some machines is a little lacking, so don't be surprised
+               if it doesn't work when virtualized.  Say n if you are unsure.
+
 endmenu
 
 menu "x86 Hacks"
index 07045f6..08aab2b 100644 (file)
@@ -165,6 +165,14 @@ static inline int get_os_coreid(int hw_coreid)
        return os_coreid_lookup[hw_coreid];
 }
 
+#ifdef CONFIG_FAST_COREID
+static inline int core_id(void)
+{
+       int ret;
+       asm volatile ("rdtscp" : "=c"(ret) : : "eax", "edx");
+       return ret;
+}
+#else
 /* core_id() returns the OS core number, not to be confused with the
  * hardware-specific core identifier (such as the lapic id) returned by
  * hw_core_id() */
@@ -172,6 +180,7 @@ static inline int core_id(void)
 {
        return get_os_coreid(hw_core_id());
 }
+#endif /* CONFIG_FAST_COREID */
 
 static inline int core_id_early(void)
 {
index 2ec57c5..6c84622 100644 (file)
@@ -134,10 +134,20 @@ void print_cpuinfo(void)
                #endif
        }
        cpuid(0x80000001, 0x0, &eax, &ebx, &ecx, &edx);
-       if (edx & (1 << 27))
+       if (edx & (1 << 27)) {
                printk("RDTSCP supported\n");
-       else
-               printk("RDTSCP not supported: don't trust detailed measurements\n");
+               /* Set core 0's id, for use during boot (if FAST_COREID) */
+               write_msr(MSR_TSC_AUX, 0);
+       } else {
+               printk("RDTSCP not supported, but emulated for userspace\n");
+               #ifdef CONFIG_FAST_COREID
+               printk("\nCONFIG_FAST_COREID selected, but RDTSCP not available!\n");
+               printk("\nRebuild your kernel without CONFIG_FAST_COREID\n\n");
+               panic("Cannot boot\n");
+               #endif
+       }
+       /* Regardless, make sure userspace can access rdtsc (and rdtscp) */
+       lcr4(rcr4() & ~CR4_TSD);
        printk("1 GB Jumbo pages %ssupported\n", edx & (1 << 26) ? "" : "not ");
        printk("FS/GS MSRs %ssupported\n", edx & (1 << 29) ? "" : "not ");
        #ifdef CONFIG_X86_64
index fd63d75..2010a3e 100644 (file)
@@ -61,6 +61,11 @@ static void init_smp_call_function(void)
 
 static void smp_final_core_init(struct hw_trapframe *hw_tf, void *data)
 {
+#ifdef CONFIG_FAST_COREID
+       /* Need to bootstrap the rdtscp MSR with our OS coreid */
+       int coreid = get_os_coreid(hw_core_id());
+       write_msr(MSR_TSC_AUX, coreid);
+#endif
        setup_default_mtrrs(data);
        smp_percpu_init();
        waiton_barrier(data);
index 05b5dd7..ec459ae 100644 (file)
@@ -36,6 +36,8 @@
 # define IA32_EFER_IA32E_ACT           (1 << 10)
 # define IA32_EFER_EXE_DIS_BIT         (1 << 11)
 
+#define MSR_TSC_AUX                                    0xc0000103
+
 #define MSR_FS_BASE                                    0xc0000100
 #define MSR_GS_BASE                                    0xc0000101
 #define MSR_KERN_GS_BASE                       0xc0000102