[RFC, patch] i386: vgetcpu(), take 2

From: Chuck Ebbert
Date: Wed Jun 21 2006 - 03:31:38 EST


Use a GDT entry's limit field to store per-cpu data for fast access
from userspace, and provide a vsyscall to access the current CPU
number stored there.

Questions:
1. Will the vdso relocation patch break this?
2. Should the version number of the vsyscall .so be incremented?

Test program using the new call:

/* vgetcpu.c: get CPU number we are running on.
* build kernel with vgetcpu patch first, then:
* gcc -o vgetcpu vgetcpu.c <srcpath>/arch/i386/kernel/vsyscall-sysenter.so
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>

extern int __vgetcpu(void);

int main(int argc, char * const argv[])
{
printf("cpu: %u\n", __vgetcpu());

return 0;
}

---
arch/i386/kernel/cpu/common.c | 3 +++
arch/i386/kernel/head.S | 8 +++++++-
arch/i386/kernel/vsyscall-getcpu.S | 25 +++++++++++++++++++++++++
arch/i386/kernel/vsyscall-int80.S | 2 ++
arch/i386/kernel/vsyscall-sysenter.S | 2 ++
arch/i386/kernel/vsyscall.lds.S | 1 +
6 files changed, 40 insertions(+), 1 deletion(-)

--- 2.6.17-32.orig/arch/i386/kernel/cpu/common.c
+++ 2.6.17-32/arch/i386/kernel/cpu/common.c
@@ -642,6 +642,9 @@ void __cpuinit cpu_init(void)
((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) |
(CPU_16BIT_STACK_SIZE - 1);

+ /* Set up GDT entry for per-cpu data */
+ *(__u64 *)(&gdt[27]) |= cpu;
+
cpu_gdt_descr->size = GDT_SIZE - 1;
cpu_gdt_descr->address = (unsigned long)gdt;

--- 2.6.17-32.orig/arch/i386/kernel/head.S
+++ 2.6.17-32/arch/i386/kernel/head.S
@@ -525,7 +525,13 @@ ENTRY(cpu_gdt_table)
.quad 0x004092000000ffff /* 0xc8 APM DS data */

.quad 0x0000920000000000 /* 0xd0 - ESPFIX 16-bit SS */
- .quad 0x0000000000000000 /* 0xd8 - unused */
+
+ /*
+ * Use a GDT entry to store per-cpu data for user space (DPL 3.)
+ * 32-bit data segment, byte granularity, base 0, limit set at runtime.
+ */
+ .quad 0x0040f20000000000 /* 0xd8 - for per-cpu user data */
+
.quad 0x0000000000000000 /* 0xe0 - unused */
.quad 0x0000000000000000 /* 0xe8 - unused */
.quad 0x0000000000000000 /* 0xf0 - unused */
--- /dev/null
+++ 2.6.17-32/arch/i386/kernel/vsyscall-getcpu.S
@@ -0,0 +1,25 @@
+/*
+ * vgetcpu
+ * This file is #include'd by vsyscall-*.S to define them after the
+ * vsyscall entry point. The kernel assumes that the addresses of these
+ * routines are constant for all vsyscall implementations.
+ */
+
+#include <linux/errno.h>
+
+ .text
+ .org __kernel_rt_sigreturn+32,0x90
+ .globl __vgetcpu
+ .type __vgetcpu,@function
+__vgetcpu:
+.LSTART_vgetcpu:
+ movl $-EFAULT,%eax
+ movl $((27<<3)|3),%edx
+ lsll %edx,%eax
+ jnz 1f
+ andl $0xff,%eax
+1:
+ ret
+.LEND_vgetcpu:
+ .size __vgetcpu,.-.LSTART_vgetcpu
+
--- 2.6.17-32.orig/arch/i386/kernel/vsyscall-int80.S
+++ 2.6.17-32/arch/i386/kernel/vsyscall-int80.S
@@ -51,3 +51,5 @@ __kernel_vsyscall:
* Get the common code for the sigreturn entry points.
*/
#include "vsyscall-sigreturn.S"
+
+#include "vsyscall-getcpu.S"
--- 2.6.17-32.orig/arch/i386/kernel/vsyscall-sysenter.S
+++ 2.6.17-32/arch/i386/kernel/vsyscall-sysenter.S
@@ -120,3 +120,5 @@ SYSENTER_RETURN:
* Get the common code for the sigreturn entry points.
*/
#include "vsyscall-sigreturn.S"
+
+#include "vsyscall-getcpu.S"
--- 2.6.17-32.orig/arch/i386/kernel/vsyscall.lds.S
+++ 2.6.17-32/arch/i386/kernel/vsyscall.lds.S
@@ -57,6 +57,7 @@ VERSION
__kernel_vsyscall;
__kernel_sigreturn;
__kernel_rt_sigreturn;
+ __vgetcpu;

local: *;
};
--
Chuck
"You can't read a newspaper if you can't read." --George W. Bush
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/