Add the vgetcpu vsyscall From: Vojtech Pavlik This patch adds a vgetcpu vsyscall, which depending on the CPU RDTSCP capability uses either the RDTSCP or CPUID to obtain a CPU and node numbers and pass them to the program. AK: slightly tweaked to have a better prototype for vgetcpu() It's better to pass the cpu / node numbers as separate arguments to avoid mistakes when going from SMP to NUMA. Signed-off-by: Vojtech Pavlik Signed-off-by: Andi Kleen --- arch/x86_64/kernel/time.c | 6 ++++-- arch/x86_64/kernel/vmlinux.lds.S | 7 +++++++ arch/x86_64/kernel/vsyscall.c | 20 ++++++++++++++++++-- include/asm-x86_64/vsyscall.h | 9 +++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) Index: linux/arch/x86_64/kernel/vsyscall.c =================================================================== --- linux.orig/arch/x86_64/kernel/vsyscall.c +++ linux/arch/x86_64/kernel/vsyscall.c @@ -38,6 +38,8 @@ int __sysctl_vsyscall __section_sysctl_vsyscall = 1; seqlock_t __xtime_lock __section_xtime_lock = SEQLOCK_UNLOCKED; +int __vgetcpu_mode __section_vgetcpu_mode; +unsigned char __cpu_to_node[NR_CPUS] __section_cpu_to_node; #include @@ -127,9 +129,22 @@ time_t __vsyscall(1) vtime(time_t *t) return __xtime.tv_sec; } -long __vsyscall(2) venosys_0(void) +long __vsyscall(2) vgetcpu(int *cpu, int *node) { - return -ENOSYS; + unsigned int dummy, p; + + if (__vgetcpu_mode == VGETCPU_RDTSCP) { + rdtscp(dummy, dummy, p); + } else { + cpuid(1, &dummy, &p, &dummy, &dummy); + p >>= 24; + p |= (__cpu_to_node[p] << 16); + } + if (cpu) + *cpu = p & 0xffff; + if (node) + *node = p >> 16; + return 0; } long __vsyscall(3) venosys_1(void) @@ -214,6 +229,7 @@ static int __init vsyscall_init(void) VSYSCALL_ADDR(__NR_vgettimeofday))); BUG_ON((unsigned long) &vtime != VSYSCALL_ADDR(__NR_vtime)); BUG_ON((VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE))); + BUG_ON((unsigned long) &vgetcpu != VSYSCALL_ADDR(__NR_vgetcpu)); map_vsyscall(); #ifdef CONFIG_SYSCTL register_sysctl_table(kernel_root_table2, 0); Index: linux/include/asm-x86_64/vsyscall.h =================================================================== --- linux.orig/include/asm-x86_64/vsyscall.h +++ linux/include/asm-x86_64/vsyscall.h @@ -6,6 +6,7 @@ enum vsyscall_num { __NR_vgettimeofday, __NR_vtime, + __NR_vgetcpu, }; #define VSYSCALL_START (-10UL << 20) @@ -16,6 +17,8 @@ enum vsyscall_num { #ifdef __KERNEL__ #define __section_vxtime __attribute__ ((unused, __section__ (".vxtime"), aligned(16))) +#define __section_vgetcpu_mode __attribute__ ((unused, __section__ (".vgetcpu_mode"), aligned(16))) +#define __section_cpu_to_node __attribute__ ((unused, __section__ (".cpu_to_node"), aligned(16))) #define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16))) #define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16))) #define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16))) @@ -27,6 +30,9 @@ enum vsyscall_num { #define VXTIME_HPET 2 #define VXTIME_PMTMR 3 +#define VGETCPU_RDTSCP 1 +#define VGETCPU_CPUID 2 + struct vxtime_data { long hpet_address; /* HPET base address */ int last; @@ -41,6 +47,8 @@ struct vxtime_data { /* vsyscall space (readonly) */ extern struct vxtime_data __vxtime; +extern int __vgetcpu_mode; +extern unsigned char __cpu_to_node[]; extern struct timespec __xtime; extern volatile unsigned long __jiffies; extern unsigned long __wall_jiffies; @@ -49,6 +57,7 @@ extern seqlock_t __xtime_lock; /* kernel space (writeable) */ extern struct vxtime_data vxtime; +extern int vgetcpu_mode; extern unsigned long wall_jiffies; extern struct timezone sys_tz; extern int sysctl_vsyscall; Index: linux/arch/x86_64/kernel/time.c =================================================================== --- linux.orig/arch/x86_64/kernel/time.c +++ linux/arch/x86_64/kernel/time.c @@ -959,7 +959,7 @@ __cpuinit int unsynchronized_tsc(void) static void __init time_init_rdtsc(void *info) { int p; - p = smp_processor_id(); + p = smp_processor_id() | (cpu_to_node(smp_processor_id()) << 16); write_rdtscp_aux(p); } @@ -976,7 +976,9 @@ void time_init_gtod(void) if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP)) { printk(KERN_INFO "time.c: Initializing RDTSCP feature.\n"); on_each_cpu(time_init_rdtsc, NULL, 1, 1); - } + vgetcpu_mode = VGETCPU_RDTSCP; + } else + vgetcpu_mode = VGETCPU_CPUID; if (vxtime.hpet_address && notsc) { timetype = hpet_use_timer ? "HPET" : "PIT/HPET"; Index: linux/arch/x86_64/kernel/vmlinux.lds.S =================================================================== --- linux.orig/arch/x86_64/kernel/vmlinux.lds.S +++ linux/arch/x86_64/kernel/vmlinux.lds.S @@ -100,6 +100,13 @@ SECTIONS .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) } vxtime = VVIRT(.vxtime); + .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) } + vgetcpu_mode = VVIRT(.vgetcpu_mode); + + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .cpu_to_node : AT(VLOAD(.cpu_to_node)) { *(.cpu_to_node) } + cpu_to_node = VVIRT(.cpu_to_node); + .wall_jiffies : AT(VLOAD(.wall_jiffies)) { *(.wall_jiffies) } wall_jiffies = VVIRT(.wall_jiffies);